Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:38:21

0001 //
0002 // Copyright (c) 2023-2025 Ivica Siladic, Bruno Iljazovic, Korina Simicevic
0003 //
0004 // Distributed under the Boost Software License, Version 1.0.
0005 // (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
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 } // end namespace boost::mqtt5::detail
0151 
0152 #endif // !BOOST_MQTT5_RE_AUTH_OP_HPP