Skip to content

Commit

Permalink
API: Implement password- and certificate-based authentication
Browse files Browse the repository at this point in the history
fixes #9086
fixes #9085
refs #9594
  • Loading branch information
Michael Friedrich committed Jul 9, 2015
1 parent f8f86d8 commit 8bf9498
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 10 deletions.
2 changes: 1 addition & 1 deletion lib/remote/CMakeLists.txt
Expand Up @@ -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
Expand Down
42 changes: 40 additions & 2 deletions lib/remote/httpconnection.cpp
Expand Up @@ -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"
Expand All @@ -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)
Expand Down Expand Up @@ -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--;
Expand Down
4 changes: 2 additions & 2 deletions lib/remote/httpdemohandler.cpp
Expand Up @@ -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());
Expand Down
2 changes: 1 addition & 1 deletion lib/remote/httpdemohandler.hpp
Expand Up @@ -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);
};

}
Expand Down
4 changes: 2 additions & 2 deletions lib/remote/httphandler.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -94,5 +94,5 @@ void HttpHandler::ProcessRequest(HttpRequest& request, HttpResponse& response)
return;
}

handler->HandleRequest(request, response);
handler->HandleRequest(user, request, response);
}
5 changes: 3 additions & 2 deletions lib/remote/httphandler.hpp
Expand Up @@ -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>
Expand All @@ -40,10 +41,10 @@ class I2_REMOTE_API HttpHandler : public Object
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;
Expand Down

0 comments on commit 8bf9498

Please sign in to comment.