// Copyright (c) 2014-2024, The Monero Project // // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once #include #include #include #include #include #include #include "wipeable_string.h" #include "http_base.h" #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net.http" namespace epee { namespace net_utils { namespace http { struct login { login() : username(), password() {} login(std::string username_, wipeable_string password_) : username(std::move(username_)), password(std::move(password_)) {} std::string username; wipeable_string password; }; //! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added. class http_server_auth { public: struct session { session(login credentials_) : credentials(std::move(credentials_)), nonce(), counter(0) {} login credentials; std::string nonce; std::uint32_t counter; }; http_server_auth() : user(), rng() {} http_server_auth(login credentials, std::function r); //! \return Auth response, or `boost::none` iff `request` had valid auth. boost::optional get_response(const http_request_info& request) { if (user) return do_get_response(request); return boost::none; } private: boost::optional do_get_response(const http_request_info& request); boost::optional user; std::function rng; }; //! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added. class http_client_auth { public: enum status : std::uint8_t { kSuccess = 0, kBadPassword, kParseFailure }; struct session { session(login credentials_) : credentials(std::move(credentials_)), server(), counter(0) {} struct keys { using algorithm = std::function; keys() : nonce(), opaque(), realm(), generator() {} keys(std::string nonce_, std::string opaque_, std::string realm_, algorithm generator_) : nonce(std::move(nonce_)) , opaque(std::move(opaque_)) , realm(std::move(realm_)) , generator(std::move(generator_)) {} std::string nonce; std::string opaque; std::string realm; algorithm generator; }; login credentials; keys server; std::uint32_t counter; }; http_client_auth() : user() {} http_client_auth(login credentials); /*! Clients receiving a 401 response code from the server should call this function to process the server auth. Then, before every client request, `get_auth_field()` should be called to retrieve the newest authorization request. \return `kBadPassword` if client will never be able to authenticate, `kParseFailure` if all server authentication responses were invalid, and `kSuccess` if `get_auth_field` is ready to generate authorization fields. */ status handle_401(const http_response_info& response) { if (user) return do_handle_401(response); return kBadPassword; } /*! After calling `handle_401`, clients should call this function to generate an authentication field for every request. \return A HTTP "Authorization" field if `handle_401(...)` previously returned `kSuccess`. */ boost::optional> get_auth_field( const boost::string_ref method, const boost::string_ref uri) { if (user) return do_get_auth_field(method, uri); return boost::none; } private: status do_handle_401(const http_response_info&); boost::optional> do_get_auth_field(boost::string_ref, boost::string_ref); boost::optional user; }; } } }