]> granicus.if.org Git - icinga2/commitdiff
Updated authentication subsystem to use SSL certificates.
authorGunnar Beutner <gunnar.beutner@netways.de>
Tue, 24 Apr 2012 13:56:48 +0000 (15:56 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 24 Apr 2012 13:56:48 +0000 (15:56 +0200)
17 files changed:
base/tlsclient.cpp
base/tlsclient.h
base/utility.cpp
base/utility.h
components/configrpc/configrpccomponent.cpp
components/configrpc/configrpccomponent.h
icinga/authenticationcomponent.cpp [deleted file]
icinga/authenticationcomponent.h [deleted file]
icinga/discoverycomponent.cpp
icinga/discoverycomponent.h
icinga/endpoint.cpp
icinga/endpoint.h
icinga/i2-icinga.h
icinga/icinga.vcxproj
icinga/icingaapplication.cpp
icinga/jsonrpcendpoint.cpp
icinga/jsonrpcendpoint.h

index 7a6d75e0e157fd72771fae4a671439baf98cffbe..d8984e5080c5350bc7cc520270cc58b71f090d7e 100644 (file)
@@ -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;
index fd248449d2776ac38dd1bd7aabe5ab6d9590e231..e441293c6e01397ca0e26d6e14a8c25cc0a639be 100644 (file)
@@ -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);
 
index 4dd4c7b7a64caff6021750a2d98ce311e43c8920..bc966350566b4fe3cb5351e656a9b8b536e0d420 100644 (file)
@@ -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;
+}
index 18c310d81c72f77f9f86fc5b3b459cd1f2a4bcd2..785ff81272d159dc990787a7e8021641a673b0da 100644 (file)
@@ -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);
 };
 
 }
index d516e70a012bd134ab7fd65bb3ec5d73c4b76436..b4a82f86cf46ec032d11a0c4c75599205d03419e 100644 (file)
@@ -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;
 }
index 0efe8bec6ca5c1538a30e7cfc01eba30f8cd3eb6..27ce4bb3bba63dd5bf3dd0b252f76e8688a22e45 100644 (file)
@@ -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 (file)
index 1452003..0000000
+++ /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<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(&params))
-               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 (file)
index 60442b8..0000000
+++ /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 */
index 88b7bbb0fce27482c358651691a71de85883bea0..d2fd5bee73a8a84a788a35a7d469aa3967939075 100644 (file)
@@ -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;
 }
index 76d1b148f4376cf1d24b9de0f066cd67692ccc50..3e8325e95e2e4a5fa4797d97c4cb17abfd7d072b 100644 (file)
@@ -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:
index 98165032980a147b7d9d9e0950ca62990aeaa45b..7d5e82f4ff86ad7db1c24e99bfa2ce46e3e6e4ce 100644 (file)
@@ -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
index 1980fdd48e89744339cba7b9e9113b2c9fd12fb2..0f22867de12bfa187dbebf06c0a055e45fc89330 100644 (file)
@@ -66,6 +66,7 @@ public:
        int CountMethodSources(void) const;
 
        Event<EventArgs> OnIdentityChanged;
+       Event<EventArgs> OnSessionEstablished;
 };
 
 }
index 6115bf4fbf11aef6d5fe5f2481bf9bce4305d62e..8209e08deb06f2af57cdf8444d46734f14ef2054 100644 (file)
@@ -19,7 +19,6 @@
 #include "icingacomponent.h"
 #include "subscriptioncomponent.h"
 #include "subscriptionmessage.h"
-#include "authenticationcomponent.h"
 #include "identitymessage.h"
 #include "discoverycomponent.h"
 
index b081daadaa858fac5d40e5bf35db1c6dedd19a13..a4ac1786626caa6f2fee6fcc4669ead0d19340fe 100644 (file)
@@ -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" />
index 6e7f8ad8687287e1f1b70494be8a4c99f9192274..833d561e47396562e499e8f9e021b9b5f2ba579e 100644 (file)
@@ -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);
 
index edb25c8bb0b88ecc6f888278ab8fd02a60e07c08..63590f8b44264f4aeffc92c93cbf50b09c2d7db4 100644 (file)
@@ -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;
+}
index ac2cfeb1ea0f5500a7ae5309acb9b393d787513e..234ccfb0e06cfc1b5f4508190bef88dab97c01e2 100644 (file)
@@ -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;