From: Michael Friedrich Date: Thu, 9 Jul 2015 13:27:14 +0000 (+0200) Subject: API: Implement password- and certificate-based authentication X-Git-Tag: v2.4.0~516 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8bf949852a7b69322177209cc8dedfb5762fd96a;p=icinga2 API: Implement password- and certificate-based authentication fixes #9086 fixes #9085 refs #9594 --- diff --git a/lib/remote/CMakeLists.txt b/lib/remote/CMakeLists.txt index f4e29c0e5..5450ceee6 100644 --- a/lib/remote/CMakeLists.txt +++ b/lib/remote/CMakeLists.txt @@ -22,7 +22,7 @@ mkclass_target(zone.ti zone.tcpp zone.thpp) set(remote_SOURCES apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp - apiuser.cpp apiuser.thpp authority.cpp endpoint.cpp endpoint.thpp + apiuser.cpp apiuser.thpp authority.cpp base64.cpp endpoint.cpp endpoint.thpp httpchunkedencoding.cpp httpconnection.cpp httpdemohandler.cpp httphandler.cpp httprequest.cpp httpresponse.cpp jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp messageorigin.cpp zone.cpp zone.thpp diff --git a/lib/remote/httpconnection.cpp b/lib/remote/httpconnection.cpp index 59bdb730d..654988ca4 100644 --- a/lib/remote/httpconnection.cpp +++ b/lib/remote/httpconnection.cpp @@ -22,6 +22,7 @@ #include "remote/apilistener.hpp" #include "remote/apifunction.hpp" #include "remote/jsonrpc.hpp" +#include "remote/base64.hpp" #include "base/dynamictype.hpp" #include "base/objectlock.hpp" #include "base/utility.hpp" @@ -42,7 +43,7 @@ HttpConnection::HttpConnection(const String& identity, bool authenticated, const boost::call_once(l_HttpConnectionOnceFlag, &HttpConnection::StaticInitialize); if (authenticated) - m_ApiUser = ApiUser::GetByName(identity); + m_ApiUser = ApiUser::GetByClientCN(identity); } void HttpConnection::StaticInitialize(void) @@ -116,8 +117,45 @@ void HttpConnection::ProcessMessageAsync(HttpRequest& request) { Log(LogInformation, "HttpConnection", "Processing Http message"); + String auth_header = request.Headers->Get("authorization"); + + String::SizeType pos = auth_header.FindFirstOf(" "); + String username, password; + + if (pos != String::NPos && auth_header.SubStr(0, pos) == "Basic") { + String credentials_base64 = auth_header.SubStr(pos + 1); + String credentials = Base64::Decode(credentials_base64); + + String::SizeType cpos = credentials.FindFirstOf(":"); + + if (cpos != String::NPos) { + username = credentials.SubStr(0, cpos); + password = credentials.SubStr(cpos + 1); + } + } + + ApiUser::Ptr user; + + if (m_ApiUser) + user = m_ApiUser; + else { + user = ApiUser::GetByName(username); + + if (!user || !user->CheckPassword(password)) + user.reset(); + } + HttpResponse response(m_Stream, request); - HttpHandler::ProcessRequest(request, response); + + if (!user) { + response.SetStatus(401, "Unauthorized"); + response.AddHeader("WWW-Authenticate", "Basic realm=\"Icinga 2\""); + String msg = "

Unauthorized

"; + response.WriteBody(msg.CStr(), msg.GetLength()); + } else { + HttpHandler::ProcessRequest(user, request, response); + } + response.Finish(); m_PendingRequests--; diff --git a/lib/remote/httpdemohandler.cpp b/lib/remote/httpdemohandler.cpp index 0553ba802..86e37d2fe 100644 --- a/lib/remote/httpdemohandler.cpp +++ b/lib/remote/httpdemohandler.cpp @@ -23,10 +23,10 @@ using namespace icinga; REGISTER_URLHANDLER("/demo", HttpDemoHandler); -void HttpDemoHandler::HandleRequest(HttpRequest& request, HttpResponse& response) +void HttpDemoHandler::HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { if (request.RequestMethod == "GET") { - String form = "
"; + String form = "

Hallo " + user->GetName() + "

"; response.SetStatus(200, "OK"); response.AddHeader("Content-Type", "text/html"); response.WriteBody(form.CStr(), form.GetLength()); diff --git a/lib/remote/httpdemohandler.hpp b/lib/remote/httpdemohandler.hpp index 1e596e421..dbece031d 100644 --- a/lib/remote/httpdemohandler.hpp +++ b/lib/remote/httpdemohandler.hpp @@ -30,7 +30,7 @@ class I2_REMOTE_API HttpDemoHandler : public HttpHandler public: DECLARE_PTR_TYPEDEFS(HttpDemoHandler); - virtual void HandleRequest(HttpRequest& request, HttpResponse& response); + virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response); }; } diff --git a/lib/remote/httphandler.cpp b/lib/remote/httphandler.cpp index 51bffc80e..377a4020d 100644 --- a/lib/remote/httphandler.cpp +++ b/lib/remote/httphandler.cpp @@ -53,7 +53,7 @@ bool HttpHandler::CanAlsoHandleUrl(const Url::Ptr& url) const return false; } -void HttpHandler::ProcessRequest(HttpRequest& request, HttpResponse& response) +void HttpHandler::ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) { Dictionary::Ptr node = m_UrlTree; HttpHandler::Ptr current_handler, handler; @@ -94,5 +94,5 @@ void HttpHandler::ProcessRequest(HttpRequest& request, HttpResponse& response) return; } - handler->HandleRequest(request, response); + handler->HandleRequest(user, request, response); } diff --git a/lib/remote/httphandler.hpp b/lib/remote/httphandler.hpp index 6456af2b2..b689a95f5 100644 --- a/lib/remote/httphandler.hpp +++ b/lib/remote/httphandler.hpp @@ -22,6 +22,7 @@ #include "remote/i2-remote.hpp" #include "remote/httpresponse.hpp" +#include "remote/apiuser.hpp" #include "base/registry.hpp" #include #include @@ -40,10 +41,10 @@ public: DECLARE_PTR_TYPEDEFS(HttpHandler); virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const; - virtual void HandleRequest(HttpRequest& request, HttpResponse& response) = 0; + virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response) = 0; static void Register(const Url::Ptr& url, const HttpHandler::Ptr& handler); - static void ProcessRequest(HttpRequest& request, HttpResponse& response); + static void ProcessRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response); private: static Dictionary::Ptr m_UrlTree;