From e5b146b7922bf4e88fd9d02f2d5bf55cbdfaadd3 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 24 Apr 2012 15:56:48 +0200 Subject: [PATCH] Updated authentication subsystem to use SSL certificates. --- base/tlsclient.cpp | 16 +++-- base/tlsclient.h | 7 +- base/utility.cpp | 12 ++++ base/utility.h | 1 + components/configrpc/configrpccomponent.cpp | 32 +++++---- components/configrpc/configrpccomponent.h | 2 +- icinga/authenticationcomponent.cpp | 73 --------------------- icinga/authenticationcomponent.h | 23 ------- icinga/discoverycomponent.cpp | 18 ++--- icinga/discoverycomponent.h | 3 +- icinga/endpoint.cpp | 2 + icinga/endpoint.h | 1 + icinga/i2-icinga.h | 1 - icinga/icinga.vcxproj | 2 - icinga/icingaapplication.cpp | 3 - icinga/jsonrpcendpoint.cpp | 9 +++ icinga/jsonrpcendpoint.h | 1 + 17 files changed, 65 insertions(+), 141 deletions(-) delete mode 100644 icinga/authenticationcomponent.cpp delete mode 100644 icinga/authenticationcomponent.h diff --git a/base/tlsclient.cpp b/base/tlsclient.cpp index 7a6d75e0e..d8984e508 100644 --- a/base/tlsclient.cpp +++ b/base/tlsclient.cpp @@ -10,14 +10,19 @@ TLSClient::TLSClient(TCPClientRole role, shared_ptr 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 TLSClient::GetClientCertificate(void) const { - return SSL_get_peer_certificate(m_SSL.get()); + return shared_ptr(SSL_get_certificate(m_SSL.get()), &TLSClient::NullCertificateDeleter); +} + +shared_ptr TLSClient::GetPeerCertificate(void) const +{ + return shared_ptr(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_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(x509Context->cert, &TLSClient::NullCertificateDeleter); client->OnVerifyCertificate(vcea); return (int)vcea.ValidCertificate; diff --git a/base/tlsclient.h b/base/tlsclient.h index fd248449d..e441293c6 100644 --- a/base/tlsclient.h +++ b/base/tlsclient.h @@ -8,6 +8,7 @@ struct I2_BASE_API VerifyCertificateEventArgs : public EventArgs { bool ValidCertificate; X509_STORE_CTX *Context; + shared_ptr 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 sslContext); - X509 *GetClientCertificate(void) const; - X509 *GetPeerCertificate(void) const; + shared_ptr GetClientCertificate(void) const; + shared_ptr GetPeerCertificate(void) const; virtual void Start(void); diff --git a/base/utility.cpp b/base/utility.cpp index 4dd4c7b7a..bc9663505 100644 --- a/base/utility.cpp +++ b/base/utility.cpp @@ -74,3 +74,15 @@ shared_ptr Utility::MakeSSLContext(string pubkey, string privkey, strin return sslContext; } + +string Utility::GetCertificateCN(const shared_ptr& 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; +} diff --git a/base/utility.h b/base/utility.h index 18c310d81..785ff8127 100644 --- a/base/utility.h +++ b/base/utility.h @@ -45,6 +45,7 @@ public: static void Daemonize(void); static shared_ptr MakeSSLContext(string pubkey, string privkey, string cakey); + static string GetCertificateCN(const shared_ptr& certificate); }; } diff --git a/components/configrpc/configrpccomponent.cpp b/components/configrpc/configrpccomponent.cpp index d516e70a0..b4a82f86c 100644 --- a/components/configrpc/configrpccomponent.cpp +++ b/components/configrpc/configrpccomponent.cpp @@ -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(ea.Source); + GetEndpointManager()->SendUnicastRequest(m_ConfigRpcEndpoint, endpoint, request); return 0; } diff --git a/components/configrpc/configrpccomponent.h b/components/configrpc/configrpccomponent.h index 0efe8bec6..27ce4bb3b 100644 --- a/components/configrpc/configrpccomponent.h +++ b/components/configrpc/configrpccomponent.h @@ -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); diff --git a/icinga/authenticationcomponent.cpp b/icinga/authenticationcomponent.cpp deleted file mode 100644 index 14520036e..000000000 --- a/icinga/authenticationcomponent.cpp +++ /dev/null @@ -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(); - 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; -} diff --git a/icinga/authenticationcomponent.h b/icinga/authenticationcomponent.h deleted file mode 100644 index 60442b84e..000000000 --- a/icinga/authenticationcomponent.h +++ /dev/null @@ -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 */ diff --git a/icinga/discoverycomponent.cpp b/icinga/discoverycomponent.cpp index 88b7bbb0f..d2fd5bee7 100644 --- a/icinga/discoverycomponent.cpp +++ b/icinga/discoverycomponent.cpp @@ -11,8 +11,6 @@ void DiscoveryComponent::Start(void) { m_DiscoveryEndpoint = make_shared(); 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(neea.Source); + GetEndpointManager()->SendUnicastRequest(m_DiscoveryEndpoint, endpoint, request); + + /* TODO: send information about this client to all other clients */ return 0; } diff --git a/icinga/discoverycomponent.h b/icinga/discoverycomponent.h index 76d1b148f..3e8325e95 100644 --- a/icinga/discoverycomponent.h +++ b/icinga/discoverycomponent.h @@ -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: diff --git a/icinga/endpoint.cpp b/icinga/endpoint.cpp index 981650329..7d5e82f4f 100644 --- a/icinga/endpoint.cpp +++ b/icinga/endpoint.cpp @@ -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 diff --git a/icinga/endpoint.h b/icinga/endpoint.h index 1980fdd48..0f22867de 100644 --- a/icinga/endpoint.h +++ b/icinga/endpoint.h @@ -66,6 +66,7 @@ public: int CountMethodSources(void) const; Event OnIdentityChanged; + Event OnSessionEstablished; }; } diff --git a/icinga/i2-icinga.h b/icinga/i2-icinga.h index 6115bf4fb..8209e08de 100644 --- a/icinga/i2-icinga.h +++ b/icinga/i2-icinga.h @@ -19,7 +19,6 @@ #include "icingacomponent.h" #include "subscriptioncomponent.h" #include "subscriptionmessage.h" -#include "authenticationcomponent.h" #include "identitymessage.h" #include "discoverycomponent.h" diff --git a/icinga/icinga.vcxproj b/icinga/icinga.vcxproj index b081daada..a4ac17866 100644 --- a/icinga/icinga.vcxproj +++ b/icinga/icinga.vcxproj @@ -11,7 +11,6 @@ - @@ -24,7 +23,6 @@ - diff --git a/icinga/icingaapplication.cpp b/icinga/icingaapplication.cpp index 6e7f8ad86..833d561e4 100644 --- a/icinga/icingaapplication.cpp +++ b/icinga/icingaapplication.cpp @@ -53,9 +53,6 @@ int IcingaApplication::Main(const vector& args) connectionCollection->OnObjectRemoved += bind_weak(&IcingaApplication::DeletedRpcConnectionHandler, shared_from_this()); - AuthenticationComponent::Ptr authenticationComponent = make_shared(); - RegisterComponent(authenticationComponent); - SubscriptionComponent::Ptr subscriptionComponent = make_shared(); RegisterComponent(subscriptionComponent); diff --git a/icinga/jsonrpcendpoint.cpp b/icinga/jsonrpcendpoint.cpp index edb25c8bb..63590f8b4 100644 --- a/icinga/jsonrpcendpoint.cpp +++ b/icinga/jsonrpcendpoint.cpp @@ -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; +} diff --git a/icinga/jsonrpcendpoint.h b/icinga/jsonrpcendpoint.h index ac2cfeb1e..234ccfb0e 100644 --- a/icinga/jsonrpcendpoint.h +++ b/icinga/jsonrpcendpoint.h @@ -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 Ptr; -- 2.40.0