re_auth_op.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. //
  2. // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
  3. //
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MQTT5_RE_AUTH_OP_hpp
  8. #define BOOST_MQTT5_RE_AUTH_OP_hpp
  9. #include <boost/mqtt5/error.hpp>
  10. #include <boost/mqtt5/reason_codes.hpp>
  11. #include <boost/mqtt5/types.hpp>
  12. #include <boost/mqtt5/detail/any_authenticator.hpp>
  13. #include <boost/mqtt5/detail/control_packet.hpp>
  14. #include <boost/mqtt5/impl/codecs/message_decoders.hpp>
  15. #include <boost/mqtt5/impl/codecs/message_encoders.hpp>
  16. #include <boost/mqtt5/impl/disconnect_op.hpp>
  17. #include <boost/asio/detached.hpp>
  18. #include <boost/asio/prepend.hpp>
  19. #include <boost/asio/recycling_allocator.hpp>
  20. #include <memory>
  21. #include <string>
  22. namespace boost::mqtt5::detail {
  23. namespace asio = boost::asio;
  24. template <typename ClientService>
  25. class re_auth_op {
  26. using client_service = ClientService;
  27. struct on_auth_data {};
  28. std::shared_ptr<client_service> _svc_ptr;
  29. any_authenticator& _auth;
  30. public:
  31. explicit re_auth_op(std::shared_ptr<client_service> svc_ptr) :
  32. _svc_ptr(std::move(svc_ptr)),
  33. _auth(_svc_ptr->_stream_context.mqtt_context().authenticator)
  34. {}
  35. re_auth_op(re_auth_op&&) noexcept = default;
  36. re_auth_op(const re_auth_op&) = delete;
  37. re_auth_op& operator=(re_auth_op&&) noexcept = default;
  38. re_auth_op& operator=(const re_auth_op&) = delete;
  39. using allocator_type = asio::recycling_allocator<void>;
  40. allocator_type get_allocator() const noexcept {
  41. return allocator_type {};
  42. }
  43. using executor_type = typename client_service::executor_type;
  44. executor_type get_executor() const noexcept {
  45. return _svc_ptr->get_executor();
  46. }
  47. void perform() {
  48. if (_auth.method().empty())
  49. return;
  50. auto auth_step = auth_step_e::client_initial;
  51. return _auth.async_auth(
  52. auth_step, "",
  53. asio::prepend(std::move(*this), on_auth_data {}, auth_step)
  54. );
  55. }
  56. void perform(decoders::auth_message auth_message) {
  57. if (_auth.method().empty())
  58. return on_auth_fail(
  59. "Unexpected AUTH received",
  60. disconnect_rc_e::protocol_error
  61. );
  62. const auto& [rc, props] = auth_message;
  63. auto auth_rc = to_reason_code<reason_codes::category::auth>(rc);
  64. if (!auth_rc.has_value())
  65. return on_auth_fail(
  66. "Malformed AUTH received: bad reason code",
  67. disconnect_rc_e::malformed_packet
  68. );
  69. const auto& server_auth_method = props[prop::authentication_method];
  70. if (!server_auth_method || *server_auth_method != _auth.method())
  71. return on_auth_fail(
  72. "Malformed AUTH received: wrong authentication method",
  73. disconnect_rc_e::protocol_error
  74. );
  75. auto auth_step = auth_rc == reason_codes::success ?
  76. auth_step_e::server_final : auth_step_e::server_challenge;
  77. auto data = props[prop::authentication_data].value_or("");
  78. return _auth.async_auth(
  79. auth_step, std::move(data),
  80. asio::prepend(std::move(*this), on_auth_data {}, auth_step)
  81. );
  82. }
  83. void operator()(
  84. on_auth_data, auth_step_e auth_step, error_code ec, std::string data
  85. ) {
  86. if (ec)
  87. return on_auth_fail(
  88. "Re-authentication: authentication fail",
  89. disconnect_rc_e::unspecified_error
  90. );
  91. if (auth_step == auth_step_e::server_final)
  92. return;
  93. auth_props props;
  94. props[prop::authentication_method] = _auth.method();
  95. props[prop::authentication_data] = std::move(data);
  96. auto rc = auth_step == auth_step_e::client_initial ?
  97. reason_codes::reauthenticate : reason_codes::continue_authentication;
  98. auto packet = control_packet<allocator_type>::of(
  99. no_pid, get_allocator(),
  100. encoders::encode_auth,
  101. rc.value(), props
  102. );
  103. auto wire_data = packet.wire_data();
  104. _svc_ptr->async_send(
  105. wire_data,
  106. no_serial, send_flag::none,
  107. asio::consign(asio::detached, std::move(packet))
  108. );
  109. }
  110. private:
  111. void on_auth_fail(std::string message, disconnect_rc_e reason) {
  112. auto props = disconnect_props {};
  113. props[prop::reason_string] = std::move(message);
  114. async_disconnect(reason, props, _svc_ptr, asio::detached);
  115. }
  116. };
  117. } // end namespace boost::mqtt5::detail
  118. #endif // !BOOST_MQTT5_RE_AUTH_OP_HPP