]> granicus.if.org Git - icinga2/commitdiff
API: Implement password- and certificate-based authentication
authorMichael Friedrich <michael.friedrich@netways.de>
Thu, 9 Jul 2015 13:27:14 +0000 (15:27 +0200)
committerMichael Friedrich <michael.friedrich@netways.de>
Thu, 9 Jul 2015 13:27:14 +0000 (15:27 +0200)
fixes #9086
fixes #9085
refs #9594

lib/remote/CMakeLists.txt
lib/remote/httpconnection.cpp
lib/remote/httpdemohandler.cpp
lib/remote/httpdemohandler.hpp
lib/remote/httphandler.cpp
lib/remote/httphandler.hpp

index f4e29c0e564e0b0ccdc9005d34a218a4d372a6ea..5450ceee6af84b946bdc208edbdb32319486abcb 100644 (file)
@@ -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
index 59bdb730ddac064e19406aaabc0145aa33011164..654988ca4b9de81ed099ad2c592af6494fdcf0e2 100644 (file)
@@ -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 = "<h1>Unauthorized</h1>";
+               response.WriteBody(msg.CStr(), msg.GetLength());
+       } else {
+               HttpHandler::ProcessRequest(user, request, response);
+       }
+
        response.Finish();
 
        m_PendingRequests--;
index 0553ba80226ad8d358a5c0c65a30ef3dfa86df23..86e37d2fefd7d43353f4c7bae67f4585ba0ec9a6 100644 (file)
@@ -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 = "<form action=\"/demo\" method=\"post\"><input type=\"text\" name=\"msg\"><input type=\"submit\"></form>";
+               String form = "<h1>Hallo " + user->GetName() + "</h1><form action=\"/demo\" method=\"post\"><input type=\"text\" name=\"msg\"><input type=\"submit\"></form>";
                response.SetStatus(200, "OK");
                response.AddHeader("Content-Type", "text/html");
                response.WriteBody(form.CStr(), form.GetLength());
index 1e596e4210b77d5ae2ba4f6b9821103edf905b18..dbece031d5f9c3b2359964fa4744e0dc5f88446e 100644 (file)
@@ -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);
 };
 
 }
index 51bffc80e23494d59e973215ec3c062520790486..377a4020def0ea77192131fbad3b657973d8da25 100644 (file)
@@ -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);
 }
index 6456af2b22da32bcc644c1c3a863d654f6b0c7a6..b689a95f5a4d33f136cc35268b1bb61d3572d914 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "remote/i2-remote.hpp"
 #include "remote/httpresponse.hpp"
+#include "remote/apiuser.hpp"
 #include "base/registry.hpp"
 #include <vector>
 #include <boost/function.hpp>
@@ -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;