mirror of https://github.com/Icinga/icinga2.git
API: Implement password- and certificate-based authentication
fixes #9086 fixes #9085 refs #9594
This commit is contained in:
parent
f8f86d89a4
commit
8bf949852a
|
@ -22,7 +22,7 @@ mkclass_target(zone.ti zone.tcpp zone.thpp)
|
||||||
|
|
||||||
set(remote_SOURCES
|
set(remote_SOURCES
|
||||||
apifunction.cpp apilistener.cpp apilistener.thpp apilistener-sync.cpp
|
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
|
httpchunkedencoding.cpp httpconnection.cpp httpdemohandler.cpp httphandler.cpp httprequest.cpp httpresponse.cpp
|
||||||
jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
|
jsonrpc.cpp jsonrpcconnection.cpp jsonrpcconnection-heartbeat.cpp
|
||||||
messageorigin.cpp zone.cpp zone.thpp
|
messageorigin.cpp zone.cpp zone.thpp
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "remote/apilistener.hpp"
|
#include "remote/apilistener.hpp"
|
||||||
#include "remote/apifunction.hpp"
|
#include "remote/apifunction.hpp"
|
||||||
#include "remote/jsonrpc.hpp"
|
#include "remote/jsonrpc.hpp"
|
||||||
|
#include "remote/base64.hpp"
|
||||||
#include "base/dynamictype.hpp"
|
#include "base/dynamictype.hpp"
|
||||||
#include "base/objectlock.hpp"
|
#include "base/objectlock.hpp"
|
||||||
#include "base/utility.hpp"
|
#include "base/utility.hpp"
|
||||||
|
@ -42,7 +43,7 @@ HttpConnection::HttpConnection(const String& identity, bool authenticated, const
|
||||||
boost::call_once(l_HttpConnectionOnceFlag, &HttpConnection::StaticInitialize);
|
boost::call_once(l_HttpConnectionOnceFlag, &HttpConnection::StaticInitialize);
|
||||||
|
|
||||||
if (authenticated)
|
if (authenticated)
|
||||||
m_ApiUser = ApiUser::GetByName(identity);
|
m_ApiUser = ApiUser::GetByClientCN(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpConnection::StaticInitialize(void)
|
void HttpConnection::StaticInitialize(void)
|
||||||
|
@ -116,8 +117,45 @@ void HttpConnection::ProcessMessageAsync(HttpRequest& request)
|
||||||
{
|
{
|
||||||
Log(LogInformation, "HttpConnection", "Processing Http message");
|
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);
|
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();
|
response.Finish();
|
||||||
|
|
||||||
m_PendingRequests--;
|
m_PendingRequests--;
|
||||||
|
|
|
@ -23,10 +23,10 @@ using namespace icinga;
|
||||||
|
|
||||||
REGISTER_URLHANDLER("/demo", HttpDemoHandler);
|
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") {
|
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.SetStatus(200, "OK");
|
||||||
response.AddHeader("Content-Type", "text/html");
|
response.AddHeader("Content-Type", "text/html");
|
||||||
response.WriteBody(form.CStr(), form.GetLength());
|
response.WriteBody(form.CStr(), form.GetLength());
|
||||||
|
|
|
@ -30,7 +30,7 @@ class I2_REMOTE_API HttpDemoHandler : public HttpHandler
|
||||||
public:
|
public:
|
||||||
DECLARE_PTR_TYPEDEFS(HttpDemoHandler);
|
DECLARE_PTR_TYPEDEFS(HttpDemoHandler);
|
||||||
|
|
||||||
virtual void HandleRequest(HttpRequest& request, HttpResponse& response);
|
virtual void HandleRequest(const ApiUser::Ptr& user, HttpRequest& request, HttpResponse& response);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,7 +53,7 @@ bool HttpHandler::CanAlsoHandleUrl(const Url::Ptr& url) const
|
||||||
return false;
|
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;
|
Dictionary::Ptr node = m_UrlTree;
|
||||||
HttpHandler::Ptr current_handler, handler;
|
HttpHandler::Ptr current_handler, handler;
|
||||||
|
@ -94,5 +94,5 @@ void HttpHandler::ProcessRequest(HttpRequest& request, HttpResponse& response)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->HandleRequest(request, response);
|
handler->HandleRequest(user, request, response);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "remote/i2-remote.hpp"
|
#include "remote/i2-remote.hpp"
|
||||||
#include "remote/httpresponse.hpp"
|
#include "remote/httpresponse.hpp"
|
||||||
|
#include "remote/apiuser.hpp"
|
||||||
#include "base/registry.hpp"
|
#include "base/registry.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
|
@ -40,10 +41,10 @@ public:
|
||||||
DECLARE_PTR_TYPEDEFS(HttpHandler);
|
DECLARE_PTR_TYPEDEFS(HttpHandler);
|
||||||
|
|
||||||
virtual bool CanAlsoHandleUrl(const Url::Ptr& url) const;
|
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 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:
|
private:
|
||||||
static Dictionary::Ptr m_UrlTree;
|
static Dictionary::Ptr m_UrlTree;
|
||||||
|
|
Loading…
Reference in New Issue