File indexing completed on 2025-09-17 08:38:21
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_MQTT5_RE_AUTH_OP_hpp
0009 #define BOOST_MQTT5_RE_AUTH_OP_hpp
0010
0011 #include <boost/mqtt5/error.hpp>
0012 #include <boost/mqtt5/reason_codes.hpp>
0013 #include <boost/mqtt5/types.hpp>
0014
0015 #include <boost/mqtt5/detail/any_authenticator.hpp>
0016 #include <boost/mqtt5/detail/control_packet.hpp>
0017
0018 #include <boost/mqtt5/impl/codecs/message_decoders.hpp>
0019 #include <boost/mqtt5/impl/codecs/message_encoders.hpp>
0020 #include <boost/mqtt5/impl/disconnect_op.hpp>
0021
0022 #include <boost/asio/detached.hpp>
0023 #include <boost/asio/prepend.hpp>
0024 #include <boost/asio/recycling_allocator.hpp>
0025
0026 #include <memory>
0027 #include <string>
0028
0029 namespace boost::mqtt5::detail {
0030
0031 namespace asio = boost::asio;
0032
0033 template <typename ClientService>
0034 class re_auth_op {
0035 using client_service = ClientService;
0036 struct on_auth_data {};
0037
0038 std::shared_ptr<client_service> _svc_ptr;
0039 any_authenticator& _auth;
0040
0041 public:
0042 explicit re_auth_op(std::shared_ptr<client_service> svc_ptr) :
0043 _svc_ptr(std::move(svc_ptr)),
0044 _auth(_svc_ptr->_stream_context.mqtt_context().authenticator)
0045 {}
0046
0047 re_auth_op(re_auth_op&&) noexcept = default;
0048 re_auth_op(const re_auth_op&) = delete;
0049
0050 re_auth_op& operator=(re_auth_op&&) noexcept = default;
0051 re_auth_op& operator=(const re_auth_op&) = delete;
0052
0053 using allocator_type = asio::recycling_allocator<void>;
0054 allocator_type get_allocator() const noexcept {
0055 return allocator_type {};
0056 }
0057
0058 using executor_type = typename client_service::executor_type;
0059 executor_type get_executor() const noexcept {
0060 return _svc_ptr->get_executor();
0061 }
0062
0063 void perform() {
0064 if (_auth.method().empty())
0065 return;
0066
0067 auto auth_step = auth_step_e::client_initial;
0068 return _auth.async_auth(
0069 auth_step, "",
0070 asio::prepend(std::move(*this), on_auth_data {}, auth_step)
0071 );
0072 }
0073
0074 void perform(decoders::auth_message auth_message) {
0075 if (_auth.method().empty())
0076 return on_auth_fail(
0077 "Unexpected AUTH received",
0078 disconnect_rc_e::protocol_error
0079 );
0080
0081 const auto& [rc, props] = auth_message;
0082 auto auth_rc = to_reason_code<reason_codes::category::auth>(rc);
0083 if (!auth_rc.has_value())
0084 return on_auth_fail(
0085 "Malformed AUTH received: bad reason code",
0086 disconnect_rc_e::malformed_packet
0087 );
0088
0089 const auto& server_auth_method = props[prop::authentication_method];
0090 if (!server_auth_method || *server_auth_method != _auth.method())
0091 return on_auth_fail(
0092 "Malformed AUTH received: wrong authentication method",
0093 disconnect_rc_e::protocol_error
0094 );
0095
0096 auto auth_step = auth_rc == reason_codes::success ?
0097 auth_step_e::server_final : auth_step_e::server_challenge;
0098 auto data = props[prop::authentication_data].value_or("");
0099
0100 return _auth.async_auth(
0101 auth_step, std::move(data),
0102 asio::prepend(std::move(*this), on_auth_data {}, auth_step)
0103 );
0104 }
0105
0106 void operator()(
0107 on_auth_data, auth_step_e auth_step, error_code ec, std::string data
0108 ) {
0109 if (ec)
0110 return on_auth_fail(
0111 "Re-authentication: authentication fail",
0112 disconnect_rc_e::unspecified_error
0113 );
0114
0115 if (auth_step == auth_step_e::server_final)
0116 return;
0117
0118 auth_props props;
0119 props[prop::authentication_method] = _auth.method();
0120 props[prop::authentication_data] = std::move(data);
0121 auto rc = auth_step == auth_step_e::client_initial ?
0122 reason_codes::reauthenticate : reason_codes::continue_authentication;
0123
0124 auto packet = control_packet<allocator_type>::of(
0125 no_pid, get_allocator(),
0126 encoders::encode_auth,
0127 rc.value(), props
0128 );
0129
0130 auto wire_data = packet.wire_data();
0131
0132 _svc_ptr->async_send(
0133 wire_data,
0134 no_serial, send_flag::none,
0135 asio::consign(asio::detached, std::move(packet))
0136 );
0137 }
0138
0139 private:
0140 void on_auth_fail(std::string message, disconnect_rc_e reason) {
0141 auto props = disconnect_props {};
0142 props[prop::reason_string] = std::move(message);
0143
0144 async_disconnect(reason, props, _svc_ptr, asio::detached);
0145 }
0146
0147 };
0148
0149
0150 }
0151
0152 #endif