mirror of https://github.com/Icinga/icinga2.git
Updated authentication subsystem to use SSL certificates.
This commit is contained in:
parent
4f6aa3236c
commit
e5b146b792
|
@ -10,14 +10,19 @@ TLSClient::TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext) : TCPCl
|
|||
m_SSLContext = sslContext;
|
||||
}
|
||||
|
||||
X509 *TLSClient::GetClientCertificate(void) const
|
||||
void TLSClient::NullCertificateDeleter(X509 *certificate)
|
||||
{
|
||||
return SSL_get_certificate(m_SSL.get());
|
||||
/* Nothing to do here. */
|
||||
}
|
||||
|
||||
X509 *TLSClient::GetPeerCertificate(void) const
|
||||
shared_ptr<X509> TLSClient::GetClientCertificate(void) const
|
||||
{
|
||||
return SSL_get_peer_certificate(m_SSL.get());
|
||||
return shared_ptr<X509>(SSL_get_certificate(m_SSL.get()), &TLSClient::NullCertificateDeleter);
|
||||
}
|
||||
|
||||
shared_ptr<X509> TLSClient::GetPeerCertificate(void) const
|
||||
{
|
||||
return shared_ptr<X509>(SSL_get_peer_certificate(m_SSL.get()), X509_free);
|
||||
}
|
||||
|
||||
void TLSClient::Start(void)
|
||||
|
@ -27,7 +32,7 @@ void TLSClient::Start(void)
|
|||
m_SSL = shared_ptr<SSL>(SSL_new(m_SSLContext.get()), SSL_free);
|
||||
|
||||
if (!m_SSL)
|
||||
; /* TODO: deal with error */
|
||||
throw OpenSSLException("SSL_new failed", ERR_get_error());
|
||||
|
||||
if (!GetClientCertificate())
|
||||
throw InvalidArgumentException("No X509 client certificate was specified.");
|
||||
|
@ -161,6 +166,7 @@ int TLSClient::SSLVerifyCertificate(int ok, X509_STORE_CTX *x509Context)
|
|||
vcea.Source = client->shared_from_this();
|
||||
vcea.ValidCertificate = (ok != 0);
|
||||
vcea.Context = x509Context;
|
||||
vcea.Certificate = shared_ptr<X509>(x509Context->cert, &TLSClient::NullCertificateDeleter);
|
||||
client->OnVerifyCertificate(vcea);
|
||||
|
||||
return (int)vcea.ValidCertificate;
|
||||
|
|
|
@ -8,6 +8,7 @@ struct I2_BASE_API VerifyCertificateEventArgs : public EventArgs
|
|||
{
|
||||
bool ValidCertificate;
|
||||
X509_STORE_CTX *Context;
|
||||
shared_ptr<X509> Certificate;
|
||||
};
|
||||
|
||||
class I2_BASE_API TLSClient : public TCPClient
|
||||
|
@ -24,6 +25,8 @@ private:
|
|||
|
||||
virtual void CloseInternal(bool from_dtor);
|
||||
|
||||
static void NullCertificateDeleter(X509 *certificate);
|
||||
|
||||
static int SSLVerifyCertificate(int ok, X509_STORE_CTX *x509Context);
|
||||
|
||||
protected:
|
||||
|
@ -32,8 +35,8 @@ protected:
|
|||
public:
|
||||
TLSClient(TCPClientRole role, shared_ptr<SSL_CTX> sslContext);
|
||||
|
||||
X509 *GetClientCertificate(void) const;
|
||||
X509 *GetPeerCertificate(void) const;
|
||||
shared_ptr<X509> GetClientCertificate(void) const;
|
||||
shared_ptr<X509> GetPeerCertificate(void) const;
|
||||
|
||||
virtual void Start(void);
|
||||
|
||||
|
|
|
@ -74,3 +74,15 @@ shared_ptr<SSL_CTX> Utility::MakeSSLContext(string pubkey, string privkey, strin
|
|||
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
string Utility::GetCertificateCN(const shared_ptr<X509>& certificate)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
int rc = X509_NAME_get_text_by_NID(X509_get_subject_name(certificate.get()), NID_commonName, buffer, sizeof(buffer));
|
||||
|
||||
if (rc == -1)
|
||||
throw InvalidArgumentException("X509 certificate has no CN attribute.");
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
static void Daemonize(void);
|
||||
|
||||
static shared_ptr<SSL_CTX> MakeSSLContext(string pubkey, string privkey, string cakey);
|
||||
static string GetCertificateCN(const shared_ptr<X509>& certificate);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@ void ConfigRpcComponent::Start(void)
|
|||
|
||||
long configSource;
|
||||
if (GetConfig()->GetPropertyInteger("configSource", &configSource) && configSource != 0) {
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::FetchObjects", bind_weak(&ConfigRpcComponent::FetchObjectsHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::FetchObjects",
|
||||
bind_weak(&ConfigRpcComponent::FetchObjectsHandler, shared_from_this()));
|
||||
|
||||
configHive->OnObjectCreated += bind_weak(&ConfigRpcComponent::LocalObjectCreatedHandler, shared_from_this());
|
||||
configHive->OnObjectRemoved += bind_weak(&ConfigRpcComponent::LocalObjectRemovedHandler, shared_from_this());
|
||||
|
@ -27,11 +28,12 @@ void ConfigRpcComponent::Start(void)
|
|||
m_ConfigRpcEndpoint->RegisterMethodSource("config::PropertyChanged");
|
||||
}
|
||||
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("auth::Welcome", bind_weak(&ConfigRpcComponent::WelcomeMessageHandler, shared_from_this()));
|
||||
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectCreated", bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectRemoved", bind_weak(&ConfigRpcComponent::RemoteObjectRemovedHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::PropertyChanged", bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectCreated",
|
||||
bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::ObjectRemoved",
|
||||
bind_weak(&ConfigRpcComponent::RemoteObjectRemovedHandler, shared_from_this()));
|
||||
m_ConfigRpcEndpoint->RegisterMethodHandler("config::PropertyChanged",
|
||||
bind_weak(&ConfigRpcComponent::RemoteObjectUpdatedHandler, shared_from_this()));
|
||||
|
||||
endpointManager->RegisterEndpoint(m_ConfigRpcEndpoint);
|
||||
|
||||
|
@ -46,22 +48,18 @@ void ConfigRpcComponent::Stop(void)
|
|||
|
||||
int ConfigRpcComponent::NewEndpointHandler(const NewEndpointEventArgs& ea)
|
||||
{
|
||||
if (ea.Endpoint->HasIdentity()) {
|
||||
JsonRpcRequest request;
|
||||
request.SetMethod("config::FetchObjects");
|
||||
|
||||
GetEndpointManager()->SendUnicastRequest(m_ConfigRpcEndpoint, ea.Endpoint, request);
|
||||
}
|
||||
ea.Endpoint->OnSessionEstablished += bind_weak(&ConfigRpcComponent::SessionEstablishedHandler, shared_from_this());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConfigRpcComponent::WelcomeMessageHandler(const NewRequestEventArgs& ea)
|
||||
int ConfigRpcComponent::SessionEstablishedHandler(const EventArgs& ea)
|
||||
{
|
||||
NewEndpointEventArgs neea;
|
||||
neea.Source = shared_from_this();
|
||||
neea.Endpoint = ea.Sender;
|
||||
NewEndpointHandler(neea);
|
||||
JsonRpcRequest request;
|
||||
request.SetMethod("config::FetchObjects");
|
||||
|
||||
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(ea.Source);
|
||||
GetEndpointManager()->SendUnicastRequest(m_ConfigRpcEndpoint, endpoint, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ private:
|
|||
VirtualEndpoint::Ptr m_ConfigRpcEndpoint;
|
||||
|
||||
int NewEndpointHandler(const NewEndpointEventArgs& ea);
|
||||
int WelcomeMessageHandler(const NewRequestEventArgs& ea);
|
||||
int SessionEstablishedHandler(const EventArgs& ea);
|
||||
|
||||
int LocalObjectCreatedHandler(const EventArgs& ea);
|
||||
int LocalObjectRemovedHandler(const EventArgs& ea);
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
#include "i2-icinga.h"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
string AuthenticationComponent::GetName(void) const
|
||||
{
|
||||
return "authenticationcomponent";
|
||||
}
|
||||
|
||||
void AuthenticationComponent::Start(void)
|
||||
{
|
||||
m_AuthenticationEndpoint = make_shared<VirtualEndpoint>();
|
||||
m_AuthenticationEndpoint->RegisterMethodHandler("auth::SetIdentity", bind_weak(&AuthenticationComponent::IdentityMessageHandler, shared_from_this()));
|
||||
m_AuthenticationEndpoint->RegisterMethodSource("auth::Welcome");
|
||||
|
||||
EndpointManager::Ptr mgr = GetEndpointManager();
|
||||
mgr->OnNewEndpoint += bind_weak(&AuthenticationComponent::NewEndpointHandler, shared_from_this());
|
||||
mgr->ForeachEndpoint(bind(&AuthenticationComponent::NewEndpointHandler, this, _1));
|
||||
mgr->RegisterEndpoint(m_AuthenticationEndpoint);
|
||||
}
|
||||
|
||||
void AuthenticationComponent::Stop(void)
|
||||
{
|
||||
EndpointManager::Ptr mgr = GetEndpointManager();
|
||||
|
||||
if (mgr)
|
||||
mgr->UnregisterEndpoint(m_AuthenticationEndpoint);
|
||||
}
|
||||
|
||||
int AuthenticationComponent::NewEndpointHandler(const NewEndpointEventArgs& neea)
|
||||
{
|
||||
if (neea.Endpoint->IsLocal() || neea.Endpoint->HasIdentity())
|
||||
return 0;
|
||||
|
||||
neea.Endpoint->AddAllowedMethodSinkPrefix("auth::");
|
||||
neea.Endpoint->AddAllowedMethodSourcePrefix("auth::");
|
||||
|
||||
neea.Endpoint->RegisterMethodSink("auth::SetIdentity");
|
||||
|
||||
JsonRpcRequest request;
|
||||
request.SetMethod("auth::SetIdentity");
|
||||
|
||||
IdentityMessage params;
|
||||
params.SetIdentity("keks");
|
||||
request.SetParams(params);
|
||||
|
||||
GetEndpointManager()->SendUnicastRequest(m_AuthenticationEndpoint, neea.Endpoint, request);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AuthenticationComponent::IdentityMessageHandler(const NewRequestEventArgs& nrea)
|
||||
{
|
||||
Message params;
|
||||
if (!nrea.Request.GetParams(¶ms))
|
||||
return 0;
|
||||
|
||||
IdentityMessage identityMessage = params;
|
||||
|
||||
string identity;
|
||||
if (!identityMessage.GetIdentity(&identity))
|
||||
return 0;
|
||||
|
||||
nrea.Sender->SetIdentity(identity);
|
||||
|
||||
/* there's no authentication for now, just tell them it's ok to send messages */
|
||||
JsonRpcRequest request;
|
||||
request.SetMethod("auth::Welcome");
|
||||
|
||||
GetEndpointManager()->SendUnicastRequest(m_AuthenticationEndpoint, nrea.Sender, request);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef AUTHENTICATIONCOMPONENT_H
|
||||
#define AUTHENTICATIONCOMPONENT_H
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
class AuthenticationComponent : public IcingaComponent
|
||||
{
|
||||
private:
|
||||
VirtualEndpoint::Ptr m_AuthenticationEndpoint;
|
||||
|
||||
int NewEndpointHandler(const NewEndpointEventArgs& neea);
|
||||
int IdentityMessageHandler(const NewRequestEventArgs& nrea);
|
||||
|
||||
public:
|
||||
virtual string GetName(void) const;
|
||||
virtual void Start(void);
|
||||
virtual void Stop(void);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* AUTHENTICATIONCOMPONENT_H */
|
|
@ -11,8 +11,6 @@ void DiscoveryComponent::Start(void)
|
|||
{
|
||||
m_DiscoveryEndpoint = make_shared<VirtualEndpoint>();
|
||||
m_DiscoveryEndpoint->RegisterMethodSource("discovery::PeerAvailable");
|
||||
m_DiscoveryEndpoint->RegisterMethodHandler("auth::Welcome",
|
||||
bind_weak(&DiscoveryComponent::WelcomeMessageHandler, shared_from_this()));
|
||||
m_DiscoveryEndpoint->RegisterMethodHandler("discovery::GetPeers",
|
||||
bind_weak(&DiscoveryComponent::GetPeersMessageHandler, shared_from_this()));
|
||||
|
||||
|
@ -29,26 +27,22 @@ void DiscoveryComponent::Stop(void)
|
|||
|
||||
int DiscoveryComponent::NewEndpointHandler(const NewEndpointEventArgs& neea)
|
||||
{
|
||||
neea.Endpoint->OnIdentityChanged += bind_weak(&DiscoveryComponent::IdentityChangedHandler, shared_from_this());
|
||||
neea.Endpoint->OnSessionEstablished += bind_weak(&DiscoveryComponent::SessionEstablishedHandler, shared_from_this());
|
||||
|
||||
/* TODO: register handler for new sink/source */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DiscoveryComponent::IdentityChangedHandler(const EventArgs& neea)
|
||||
{
|
||||
/* TODO: send information about this client to all other clients */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DiscoveryComponent::WelcomeMessageHandler(const NewRequestEventArgs& nrea)
|
||||
int DiscoveryComponent::SessionEstablishedHandler(const EventArgs& neea)
|
||||
{
|
||||
JsonRpcRequest request;
|
||||
request.SetMethod("discovery::GetPeers");
|
||||
|
||||
GetEndpointManager()->SendUnicastRequest(m_DiscoveryEndpoint, nrea.Sender, request);
|
||||
Endpoint::Ptr endpoint = static_pointer_cast<Endpoint>(neea.Source);
|
||||
GetEndpointManager()->SendUnicastRequest(m_DiscoveryEndpoint, endpoint, request);
|
||||
|
||||
/* TODO: send information about this client to all other clients */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@ private:
|
|||
IcingaApplication::Ptr GetIcingaApplication(void) const;
|
||||
|
||||
int NewEndpointHandler(const NewEndpointEventArgs& neea);
|
||||
int IdentityChangedHandler(const EventArgs& neea);
|
||||
int WelcomeMessageHandler(const NewRequestEventArgs& nrea);
|
||||
int SessionEstablishedHandler(const EventArgs& neea);
|
||||
int GetPeersMessageHandler(const NewRequestEventArgs& nrea);
|
||||
|
||||
public:
|
||||
|
|
|
@ -14,6 +14,8 @@ void Endpoint::SetIdentity(string identity)
|
|||
EventArgs ea;
|
||||
ea.Source = shared_from_this();
|
||||
OnIdentityChanged(ea);
|
||||
|
||||
OnSessionEstablished(ea);
|
||||
}
|
||||
|
||||
bool Endpoint::HasIdentity(void) const
|
||||
|
|
|
@ -66,6 +66,7 @@ public:
|
|||
int CountMethodSources(void) const;
|
||||
|
||||
Event<EventArgs> OnIdentityChanged;
|
||||
Event<EventArgs> OnSessionEstablished;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "icingacomponent.h"
|
||||
#include "subscriptioncomponent.h"
|
||||
#include "subscriptionmessage.h"
|
||||
#include "authenticationcomponent.h"
|
||||
#include "identitymessage.h"
|
||||
#include "discoverycomponent.h"
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="authenticationcomponent.cpp" />
|
||||
<ClCompile Include="discoverycomponent.cpp" />
|
||||
<ClCompile Include="endpoint.cpp" />
|
||||
<ClCompile Include="endpointmanager.cpp" />
|
||||
|
@ -24,7 +23,6 @@
|
|||
<ClCompile Include="virtualendpoint.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="authenticationcomponent.h" />
|
||||
<ClInclude Include="discoverycomponent.h" />
|
||||
<ClInclude Include="endpoint.h" />
|
||||
<ClInclude Include="endpointmanager.h" />
|
||||
|
|
|
@ -53,9 +53,6 @@ int IcingaApplication::Main(const vector<string>& args)
|
|||
|
||||
connectionCollection->OnObjectRemoved += bind_weak(&IcingaApplication::DeletedRpcConnectionHandler, shared_from_this());
|
||||
|
||||
AuthenticationComponent::Ptr authenticationComponent = make_shared<AuthenticationComponent>();
|
||||
RegisterComponent(authenticationComponent);
|
||||
|
||||
SubscriptionComponent::Ptr subscriptionComponent = make_shared<SubscriptionComponent>();
|
||||
RegisterComponent(subscriptionComponent);
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ void JsonRpcEndpoint::SetClient(JsonRpcClient::Ptr client)
|
|||
client->OnNewMessage += bind_weak(&JsonRpcEndpoint::NewMessageHandler, shared_from_this());
|
||||
client->OnClosed += bind_weak(&JsonRpcEndpoint::ClientClosedHandler, shared_from_this());
|
||||
client->OnError += bind_weak(&JsonRpcEndpoint::ClientErrorHandler, shared_from_this());
|
||||
client->OnVerifyCertificate += bind_weak(&JsonRpcEndpoint::VerifyCertificateHandler, shared_from_this());
|
||||
}
|
||||
|
||||
bool JsonRpcEndpoint::IsLocal(void) const
|
||||
|
@ -185,3 +186,11 @@ int JsonRpcEndpoint::ClientReconnectHandler(const TimerEventArgs& ea)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JsonRpcEndpoint::VerifyCertificateHandler(const VerifyCertificateEventArgs& ea)
|
||||
{
|
||||
if (ea.Certificate && ea.ValidCertificate)
|
||||
SetIdentity(Utility::GetCertificateCN(ea.Certificate));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ private:
|
|||
int ClientClosedHandler(const EventArgs& ea);
|
||||
int ClientErrorHandler(const SocketErrorEventArgs& ea);
|
||||
int ClientReconnectHandler(const TimerEventArgs& ea);
|
||||
int VerifyCertificateHandler(const VerifyCertificateEventArgs& ea);
|
||||
|
||||
public:
|
||||
typedef shared_ptr<JsonRpcEndpoint> Ptr;
|
||||
|
|
Loading…
Reference in New Issue