diff options
author | Lee Clagett <code@leeclagett.com> | 2017-02-05 17:48:03 -0500 |
---|---|---|
committer | Lee Clagett <code@leeclagett.com> | 2017-02-06 01:15:41 -0500 |
commit | ce7fcbb4aea884bb4bf433cf419ffa267f859c87 (patch) | |
tree | e8fb644b62006d78f801d739fbebad50f2c2409d /contrib/epee/include | |
parent | Merge pull request #1669 (diff) | |
download | monero-ce7fcbb4aea884bb4bf433cf419ffa267f859c87.tar.xz |
Add server auth to monerod, and client auth to wallet-cli and wallet-rpc
Diffstat (limited to 'contrib/epee/include')
-rw-r--r-- | contrib/epee/include/net/http_base.h | 12 | ||||
-rw-r--r-- | contrib/epee/include/net/http_client.h | 95 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.h | 1 | ||||
-rw-r--r-- | contrib/epee/include/net/http_protocol_handler.inl | 7 | ||||
-rw-r--r-- | contrib/epee/include/net/http_server_impl_base.h | 4 | ||||
-rw-r--r-- | contrib/epee/include/storages/http_abstract_invoke.h | 11 |
6 files changed, 85 insertions, 45 deletions
diff --git a/contrib/epee/include/net/http_base.h b/contrib/epee/include/net/http_base.h index d8e31521f..e5aa06cb4 100644 --- a/contrib/epee/include/net/http_base.h +++ b/contrib/epee/include/net/http_base.h @@ -29,6 +29,9 @@ #pragma once #include <boost/lexical_cast.hpp> #include <boost/regex.hpp> +#include <boost/utility/string_ref.hpp> +#include <string> +#include <utility> #include "string_tools.h" @@ -90,6 +93,15 @@ namespace net_utils return std::string(); } + static inline void add_field(std::string& out, const boost::string_ref name, const boost::string_ref value) + { + out.append(name.data(), name.size()).append(": "); + out.append(value.data(), value.size()).append("\r\n"); + } + static inline void add_field(std::string& out, const std::pair<std::string, std::string>& field) + { + add_field(out, field.first, field.second); + } struct http_header_info diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index c5aeb9251..3d8c759cd 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -30,6 +30,8 @@ #include <boost/shared_ptr.hpp> #include <boost/regex.hpp> #include <boost/lexical_cast.hpp> +#include <boost/optional/optional.hpp> +#include <boost/utility/string_ref.hpp> //#include <mbstring.h> #include <algorithm> #include <cctype> @@ -45,6 +47,7 @@ #include "string_tools.h" #include "reg_exp_definer.h" #include "http_base.h" +#include "http_auth.h" #include "to_nonconst_iterator.h" #include "net_parse_helpers.h" @@ -236,9 +239,6 @@ using namespace std; class http_simple_client: public i_target_handler { - public: - - private: enum reciev_machine_state { @@ -263,6 +263,7 @@ using namespace std; blocked_mode_client m_net_client; std::string m_host_buff; std::string m_port; + http_client_auth m_auth; std::string m_header_cache; http_response_info m_response_info; size_t m_len_in_summary; @@ -280,6 +281,7 @@ using namespace std; , m_net_client() , m_host_buff() , m_port() + , m_auth() , m_header_cache() , m_response_info() , m_len_in_summary(0) @@ -291,21 +293,22 @@ using namespace std; , m_lock() {} - bool set_server(const std::string& address) + bool set_server(const std::string& address, boost::optional<login> user) { http::url_content parsed{}; const bool r = parse_url(address, parsed); CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address); - set_server(std::move(parsed.host), std::to_string(parsed.port)); + set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user)); return true; } - void set_server(std::string host, std::string port) + void set_server(std::string host, std::string port, boost::optional<login> user) { CRITICAL_REGION_LOCAL(m_lock); disconnect(); m_host_buff = std::move(host); m_port = std::move(port); + m_auth = user ? http_client_auth{std::move(*user)} : http_client_auth{}; } bool connect(std::chrono::milliseconds timeout) @@ -335,14 +338,14 @@ using namespace std; } //--------------------------------------------------------------------------- inline - bool invoke_get(const std::string& uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + bool invoke_get(const boost::string_ref uri, std::chrono::milliseconds timeout, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); return invoke(uri, "GET", body, timeout, ppresponse_info, additional_params); } //--------------------------------------------------------------------------- - inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + inline bool invoke(const boost::string_ref uri, const boost::string_ref method, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); if(!is_connected()) @@ -354,32 +357,64 @@ using namespace std; return false; } } - m_response_info.clear(); - std::string req_buff = method + " "; - req_buff += uri + " HTTP/1.1\r\n" + - "Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast<std::string>(body.size()) + "\r\n"; + std::string req_buff{}; + req_buff.reserve(2048); + req_buff.append(method.data(), method.size()).append(" ").append(uri.data(), uri.size()).append(" HTTP/1.1\r\n"); + add_field(req_buff, "Host", m_host_buff); + add_field(req_buff, "Content-Length", std::to_string(body.size())); //handle "additional_params" - for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++) - req_buff += it->first + ": " + it->second + "\r\n"; - req_buff += "\r\n"; - //-- - - bool res = m_net_client.send(req_buff, timeout); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - if(body.size()) - res = m_net_client.send(body, timeout); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - - if(ppresponse_info) - *ppresponse_info = &m_response_info; - - m_state = reciev_machine_state_header; - return handle_reciev(timeout); + for(const auto& field : additional_params) + add_field(req_buff, field); + + for (unsigned sends = 0; sends < 2; ++sends) + { + const std::size_t initial_size = req_buff.size(); + const auto auth = m_auth.get_auth_field(method, uri); + if (auth) + add_field(req_buff, *auth); + + req_buff += "\r\n"; + //-- + + bool res = m_net_client.send(req_buff, timeout); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + if(body.size()) + res = m_net_client.send(body, timeout); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + + + m_response_info.clear(); + m_state = reciev_machine_state_header; + if (!handle_reciev(timeout)) + return false; + if (m_response_info.m_response_code != 401) + { + if(ppresponse_info) + *ppresponse_info = std::addressof(m_response_info); + return true; + } + + switch (m_auth.handle_401(m_response_info)) + { + case http_client_auth::kSuccess: + break; + case http_client_auth::kBadPassword: + sends = 2; + break; + default: + case http_client_auth::kParseFailure: + LOG_ERROR("Bad server response for authentication"); + return false; + } + req_buff.resize(initial_size); // rollback for new auth generation + } + LOG_ERROR("Client has incorrect username/password for server requiring authentication"); + return false; } //--------------------------------------------------------------------------- - inline bool invoke_post(const std::string& uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + inline bool invoke_post(const boost::string_ref uri, const std::string& body, std::chrono::milliseconds timeout, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) { CRITICAL_REGION_LOCAL(m_lock); return invoke(uri, "POST", body, timeout, ppresponse_info, additional_params); @@ -730,7 +765,7 @@ using namespace std; else if(result[i++].matched)//"User-Agent" body_info.m_user_agent = result[field_val]; else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) - {;} + body_info.m_etc_fields.emplace_back(result[11], result[field_val]); else {CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<<m_cache_to_process);} diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h index c2e44c536..babe49ad7 100644 --- a/contrib/epee/include/net/http_protocol_handler.h +++ b/contrib/epee/include/net/http_protocol_handler.h @@ -54,7 +54,6 @@ namespace net_utils struct http_server_config { std::string m_folder; - std::string m_required_user_agent; boost::optional<login> m_user; critical_section m_lock; }; diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index 5bfaf4767..d9eca2479 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -390,13 +390,6 @@ namespace net_utils return false; } - if (!m_config.m_required_user_agent.empty() && m_query_info.m_header_info.m_user_agent != m_config.m_required_user_agent) - { - LOG_ERROR("simple_http_connection_handler<t_connection_context>::analize_cached_request_header_and_invoke_state(): unexpected user agent: " << m_query_info.m_header_info.m_user_agent); - m_state = http_state_error; - return false; - } - m_cache.erase(0, pos); std::string req_command_str = m_query_info.m_full_request_str; diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h index f2a580167..2a762b3ca 100644 --- a/contrib/epee/include/net/http_server_impl_base.h +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -56,7 +56,7 @@ namespace epee {} bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0", - std::string user_agent = "", boost::optional<net_utils::http::login> user = boost::none) + boost::optional<net_utils::http::login> user = boost::none) { //set self as callback handler @@ -65,8 +65,6 @@ namespace epee //here set folder for hosting reqests m_net_server.get_config_object().m_folder = ""; - // workaround till we get auth/encryption - m_net_server.get_config_object().m_required_user_agent = std::move(user_agent); m_net_server.get_config_object().m_user = std::move(user); LOG_PRINT_L0("Binding on " << bind_ip << ":" << bind_port); diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index 36177c7e0..47981acb3 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -26,6 +26,9 @@ // #pragma once +#include <boost/utility/string_ref.hpp> +#include <chrono> +#include <string> #include "portable_storage_template_helper.h" #include "net/http_base.h" #include "net/http_server_handlers_map2.h" @@ -35,7 +38,7 @@ namespace epee namespace net_utils { template<class t_request, class t_response, class t_transport> - bool invoke_http_json(const std::string& uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& method = "GET") + bool invoke_http_json(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const boost::string_ref method = "GET") { std::string req_param; if(!serialization::store_t_to_json(out_struct, req_param)) @@ -66,7 +69,7 @@ namespace epee template<class t_request, class t_response, class t_transport> - bool invoke_http_bin(const std::string& uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& method = "GET") + bool invoke_http_bin(const boost::string_ref uri, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const boost::string_ref method = "GET") { std::string req_param; if(!serialization::store_t_to_binary(out_struct, req_param)) @@ -95,7 +98,7 @@ namespace epee } template<class t_request, class t_response, class t_transport> - bool invoke_http_json_rpc(const std::string& uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& http_method = "GET", const std::string& req_id = "0") + bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request& out_struct, t_response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const boost::string_ref http_method = "GET", const std::string& req_id = "0") { epee::json_rpc::request<t_request> req_t = AUTO_VAL_INIT(req_t); req_t.jsonrpc = "2.0"; @@ -117,7 +120,7 @@ namespace epee } template<class t_command, class t_transport> - bool invoke_http_json_rpc(const std::string& uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const std::string& http_method = "GET", const std::string& req_id = "0") + bool invoke_http_json_rpc(const boost::string_ref uri, typename t_command::request& out_struct, typename t_command::response& result_struct, t_transport& transport, std::chrono::milliseconds timeout = std::chrono::seconds(5), const boost::string_ref http_method = "GET", const std::string& req_id = "0") { return invoke_http_json_rpc(uri, t_command::methodname(), out_struct, result_struct, transport, timeout, http_method, req_id); } |