From 678650beaff02b59491233b43aee2ffc5e660e6d Mon Sep 17 00:00:00 2001 From: hagen Date: Wed, 27 Apr 2016 00:00:00 +0000 Subject: [PATCH] * HTTPServer.{cpp,h}: basic auth --- HTTPServer.cpp | 61 +++++++++++++++++++++++++++++++++++++++++++++++++- HTTPServer.h | 8 ++++--- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 7dc8d910..8d9be41f 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -10,6 +10,7 @@ #include "Base.h" #include "FS.h" #include "Log.h" +#include "Config.h" #include "Tunnel.h" #include "TransitTunnel.h" #include "Transports.h" @@ -640,7 +641,16 @@ namespace http { s << "
\r\n"<< std::endl; } } - + + HTTPConnection::HTTPConnection (std::shared_ptr socket): + m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0) + { + /* cache options */ + i2p::config::GetOption("http.auth", needAuth); + i2p::config::GetOption("http.user", user); + i2p::config::GetOption("http.pass", pass); + }; + void HTTPConnection::Receive () { m_Socket->async_read_some (boost::asio::buffer (m_Buffer, HTTP_CONNECTION_BUFFER_SIZE), @@ -672,6 +682,7 @@ namespace http { } if (ret == 0) return; /* need more data */ + HandleRequest (request); } @@ -684,11 +695,44 @@ namespace http { m_Socket->close (); } + bool HTTPConnection::CheckAuth (const HTTPReq & req) { + /* method #1: http://user:pass@127.0.0.1:7070/ */ + if (req.uri.find('@') != std::string::npos) { + URL url; + if (url.parse(req.uri) && url.user == user && url.pass == pass) + return true; + } + /* method #2: 'Authorization' header sent */ + if (req.headers.count("Authorization") > 0) { + std::string provided = req.headers.find("Authorization")->second; + std::string expected = user + ":" + pass; + char b64_creds[64]; + std::size_t len = 0; + len = i2p::data::ByteStreamToBase64((unsigned char *)expected.c_str(), expected.length(), b64_creds, sizeof(b64_creds)); + b64_creds[len] = '\0'; + expected = "Basic "; + expected += b64_creds; + if (provided == expected) + return true; + } + + LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); + return false; + } + void HTTPConnection::HandleRequest (const HTTPReq & req) { std::stringstream s; std::string content; HTTPRes res; + + if (needAuth && !CheckAuth(req)) { + res.code = 401; + res.headers.insert(std::pair("WWW-Authenticate", "Basic realm=\"WebAdmin\"")); + SendReply(res, content); + return; + } + // Html5 head start ShowPageHead (s); if (req.uri.find("page=") != std::string::npos) @@ -797,6 +841,21 @@ namespace http { void HTTPServer::Start () { + bool needAuth; i2p::config::GetOption("http.auth", needAuth); + std::string user; i2p::config::GetOption("http.user", user); + std::string pass; i2p::config::GetOption("http.pass", pass); + /* generate pass if needed */ + if (needAuth && pass == "") { + char alnum[] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + pass.resize(16); + for (size_t i = 0; i < pass.size(); i++) { + pass[i] = alnum[rand() % (sizeof(alnum) - 1)]; + } + i2p::config::SetOption("http.pass", pass); + LogPrint(eLogInfo, "HTTPServer: password set to ", pass); + } m_Thread = std::unique_ptr(new std::thread (std::bind (&HTTPServer::Run, this))); m_Acceptor.listen (); Accept (); diff --git a/HTTPServer.h b/HTTPServer.h index 72a0c383..2635c3be 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -11,9 +11,7 @@ namespace http { { public: - HTTPConnection (std::shared_ptr socket): - m_Socket (socket), m_Timer (socket->get_io_service ()), - m_BufferLen (0) {}; + HTTPConnection (std::shared_ptr socket); void Receive (); private: @@ -22,6 +20,7 @@ namespace http { void Terminate (const boost::system::error_code& ecode); void RunRequest (); + bool CheckAuth (const HTTPReq & req); void HandleRequest (const HTTPReq & req); void HandlePage (const HTTPReq & req, HTTPRes & res, std::stringstream& data); void HandleCommand (const HTTPReq & req, HTTPRes & res, std::stringstream& data); @@ -33,6 +32,9 @@ namespace http { boost::asio::deadline_timer m_Timer; char m_Buffer[HTTP_CONNECTION_BUFFER_SIZE + 1]; size_t m_BufferLen; + bool needAuth; + std::string user; + std::string pass; }; class HTTPServer