directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kayyag...@apache.org
Subject svn commit: r805871 - in /directory/apacheds/trunk: protocol-ldap/src/main/java/org/apache/directory/server/ldap/ server-integ/src/test/java/org/apache/directory/server/ssl/
Date Wed, 19 Aug 2009 16:34:44 GMT
Author: kayyagari
Date: Wed Aug 19 16:34:44 2009
New Revision: 805871

URL: http://svn.apache.org/viewvc?rev=805871&view=rev
Log:
o support for reloading ssl context (DIRSERVER-1373)
o yet to find solution for some of the issues raised in DIRSERVER-1373 like what happens to
existing connections during ssl context reload

Modified:
    directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/LdapServer.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/BogusTrustManagerFactory.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/LdapsIT.java
    directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/StartTlsIT.java

Modified: directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/LdapServer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/LdapServer.java?rev=805871&r1=805870&r2=805871&view=diff
==============================================================================
--- directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/LdapServer.java
(original)
+++ directory/apacheds/trunk/protocol-ldap/src/main/java/org/apache/directory/server/ldap/LdapServer.java
Wed Aug 19 16:34:44 2009
@@ -35,22 +35,24 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.naming.NamingException;
 
 import org.apache.directory.server.core.DirectoryService;
 import org.apache.directory.server.core.partition.PartitionNexus;
 import org.apache.directory.server.core.security.CoreKeyStoreSpi;
-import org.apache.directory.server.ldap.handlers.LdapRequestHandler;
 import org.apache.directory.server.ldap.handlers.AbandonHandler;
 import org.apache.directory.server.ldap.handlers.AddHandler;
 import org.apache.directory.server.ldap.handlers.BindHandler;
 import org.apache.directory.server.ldap.handlers.CompareHandler;
 import org.apache.directory.server.ldap.handlers.DeleteHandler;
 import org.apache.directory.server.ldap.handlers.ExtendedHandler;
+import org.apache.directory.server.ldap.handlers.LdapRequestHandler;
 import org.apache.directory.server.ldap.handlers.ModifyDnHandler;
 import org.apache.directory.server.ldap.handlers.ModifyHandler;
 import org.apache.directory.server.ldap.handlers.SearchHandler;
 import org.apache.directory.server.ldap.handlers.UnbindHandler;
 import org.apache.directory.server.ldap.handlers.bind.MechanismHandler;
+import org.apache.directory.server.ldap.handlers.extended.StartTlsHandler;
 import org.apache.directory.server.ldap.handlers.ssl.LdapsInitializer;
 import org.apache.directory.server.ldap.replication.ReplicationSystem;
 import org.apache.directory.server.protocol.shared.DirectoryBackedService;
@@ -215,6 +217,10 @@
     
     private ReplicationSystem replicationSystem;
 
+    private KeyStore keyStore = null;
+
+    private IoFilterChainBuilder chainBuilder;
+    
     /**
      * Creates an LDAP protocol provider.
      */
@@ -315,6 +321,77 @@
         }
     }
 
+    
+    /**
+     * loads the digital certificate either from a keystore file or from the admin entry
in DIT
+     */
+    private void loadKeyStore() throws Exception
+    {
+        if ( StringTools.isEmpty( keystoreFile ) )
+        {
+            Provider provider = Security.getProvider( "SUN" );
+            LOG.debug( "provider = {}", provider );
+            CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( getDirectoryService()
);
+            keyStore = new KeyStore( coreKeyStoreSpi, provider, "JKS" ) {};
+            
+            try
+            {
+                keyStore.load( null, null );
+            }
+            catch ( Exception e )
+            {
+                // nothing really happens with this keystore
+            }
+        }
+        else
+        {
+            keyStore = KeyStore.getInstance( KeyStore.getDefaultType() );
+            FileInputStream fis = new FileInputStream( keystoreFile );
+            
+            keyStore.load( fis, null );
+        }
+    }
+
+    
+    /**
+     * reloads the SSL context by replacing the existing SslFilter
+     * with a new SslFilter after reloading the keystore.
+     * 
+     * Note: should be called to reload the keystore after changing the digital certificate.
+     */
+    public void reloadSslContext() throws Exception
+    {
+        if( !started )
+        {
+            return;
+        }
+
+        LOG.info( "reloading SSL context..." );
+        
+        loadKeyStore();
+        
+        DefaultIoFilterChainBuilder dfcb = ( ( DefaultIoFilterChainBuilder ) chainBuilder
);
+        String sslFilterName = "sslFilter";
+        if( dfcb.contains( sslFilterName ) )
+        {
+            DefaultIoFilterChainBuilder newChain = ( DefaultIoFilterChainBuilder ) LdapsInitializer.init(
keyStore, certificatePassword );
+            dfcb.replace( sslFilterName, newChain.get( sslFilterName ) );
+            newChain = null;
+        }
+
+        StartTlsHandler handler = ( StartTlsHandler ) getExtendedOperationHandler( StartTlsHandler.EXTENSION_OID
);
+        if( handler != null )
+        {
+            //FIXME dirty hack. IMO StartTlsHandler's code requires a cleanup
+            // cause the keystore loading and sslcontext creation code is duplicated
+            // both in the LdapService as well as StatTlsHandler
+            handler.setLdapServer( this );
+        }
+        
+        LOG.info( "reloaded SSL context successfully" );
+    }
+
+    
     /**
      * @throws IOException if we cannot bind to the specified port
      * @throws NamingException if the LDAP server cannot be started
@@ -338,33 +415,7 @@
             
             if ( transport.isSSLEnabled() )
             {
-                KeyStore keyStore = null;
-                
-                if ( StringTools.isEmpty( keystoreFile ) )
-                {
-                    Provider provider = Security.getProvider( "SUN" );
-                    LOG.debug( "provider = {}", provider );
-                    CoreKeyStoreSpi coreKeyStoreSpi = new CoreKeyStoreSpi( getDirectoryService()
);
-                    keyStore = new AdsKeyStore( coreKeyStoreSpi, provider, "JKS" );
-                    
-                    try
-                    {
-                        keyStore.load( null, null );
-                    }
-                    catch ( Exception e )
-                    {
-                        // nothing really happens with this keystore
-                    }
-                }
-                else
-                {
-                    keyStore = AdsKeyStore.getInstance( KeyStore.getDefaultType() );
-                    FileInputStream fis = new FileInputStream( keystoreFile );
-                    
-                    
-                    keyStore.load( fis, null );
-                }
-                
+                loadKeyStore();
                 chain = LdapsInitializer.init( keyStore, certificatePassword );
             }
             else
@@ -479,7 +530,9 @@
             // Set the backlog to the default value when it's below 0
             transport.setBackLog( 50 );
         }
-
+        
+        this.chainBuilder = chainBuilder;
+        
         PartitionNexus nexus = getDirectoryService().getPartitionNexus();
 
         for ( ExtendedOperationHandler h : extendedOperationHandlers )

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/BogusTrustManagerFactory.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/BogusTrustManagerFactory.java?rev=805871&r1=805870&r2=805871&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/BogusTrustManagerFactory.java
(original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/BogusTrustManagerFactory.java
Wed Aug 19 16:34:44 2009
@@ -40,6 +40,11 @@
  */
 class BogusTrustManagerFactory extends TrustManagerFactorySpi
 {
+    /**
+     * Hack to be able to access the last received server certificate from unit tests.
+     * Use with care, this is in no way thread safe!
+     */
+    static X509Certificate[] lastReceivedServerCertificates;
 
     static final X509TrustManager X509 = new X509TrustManager()
     {
@@ -50,6 +55,7 @@
 
         public void checkServerTrusted( X509Certificate[] x509Certificates, String s ) throws
CertificateException
         {
+            lastReceivedServerCertificates = x509Certificates;
         }
 
 

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/LdapsIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/LdapsIT.java?rev=805871&r1=805870&r2=805871&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/LdapsIT.java
(original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/LdapsIT.java
Wed Aug 19 16:34:44 2009
@@ -22,10 +22,12 @@
 
 import org.apache.directory.server.core.DefaultDirectoryService;
 import org.apache.directory.server.core.DirectoryService;
+import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.server.core.integ.IntegrationUtils;
 import org.apache.directory.server.core.integ.Level;
 import org.apache.directory.server.core.integ.annotations.CleanupLevel;
 import org.apache.directory.server.core.integ.annotations.Factory;
+import org.apache.directory.server.core.security.TlsKeyGenerator;
 import org.apache.directory.server.integ.LdapServerFactory;
 import org.apache.directory.server.integ.SiRunner;
 import org.apache.directory.server.ldap.LdapServer;
@@ -37,11 +39,12 @@
 import org.apache.directory.server.ldap.handlers.bind.ntlm.NtlmMechanismHandler;
 import org.apache.directory.server.ldap.handlers.extended.StoredProcedureExtendedOperationHandler;
 import org.apache.directory.server.protocol.shared.transport.TcpTransport;
-import org.apache.directory.server.ssl.SSLSocketFactory;
 import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
+import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.mina.util.AvailablePortFinder;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
 import javax.naming.NamingException;
@@ -51,7 +54,9 @@
 import javax.naming.directory.BasicAttributes;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.ModificationItem;
 
+import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
@@ -163,4 +168,56 @@
 
         assertNotNull( person );
     }
+
+    /**
+     * Test for DIRSERVER-1373.
+     */
+    @Test
+    public void testUpdateCertificate() throws Exception
+    {
+        // create a secure connection
+        Hashtable<String, String> env = new Hashtable<String, String>();
+        env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
+        env.put( "java.naming.provider.url", "ldaps://localhost:" + ldapServer.getPortSSL()
);
+        env.put( "java.naming.ldap.factory.socket", SSLSocketFactory.class.getName() );
+        env.put( "java.naming.security.principal", "uid=admin,ou=system" );
+        env.put( "java.naming.security.credentials", "secret" );
+        env.put( "java.naming.security.authentication", "simple" );
+        InitialDirContext ctx = new InitialDirContext( env );
+
+        // create a new certificate
+        String newIssuerDN = "cn=new_issuer_dn";
+        String newSubjectDN = "cn=new_subject_dn";
+        ServerEntry entry = ldapServer.getDirectoryService().getAdminSession().lookup(
+            new LdapDN( "uid=admin,ou=system" ) );
+        TlsKeyGenerator.addKeyPair( entry, newIssuerDN, newSubjectDN, "RSA" );
+
+        // now update the certificate (over the wire)
+        ModificationItem[] mods = new ModificationItem[3];
+        mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.PRIVATE_KEY_AT, entry.get( TlsKeyGenerator.PRIVATE_KEY_AT ).getBytes()
) );
+        mods[1] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.PUBLIC_KEY_AT, entry.get( TlsKeyGenerator.PUBLIC_KEY_AT ).getBytes()
) );
+        mods[2] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.USER_CERTIFICATE_AT, entry.get( TlsKeyGenerator.USER_CERTIFICATE_AT
).getBytes() ) );
+        ctx.modifyAttributes( "uid=admin,ou=system", mods );
+        ctx.close();
+
+        ldapServer.reloadSslContext();
+        
+        // create a secure connection
+        ctx = new InitialDirContext( env );
+
+        // check the received certificate, it must contain the updated server certificate
+        X509Certificate[] lastReceivedServerCertificates = BogusTrustManagerFactory.lastReceivedServerCertificates;
+        assertNotNull( lastReceivedServerCertificates );
+        assertEquals( 1, lastReceivedServerCertificates.length );
+        String issuerDN = lastReceivedServerCertificates[0].getIssuerDN().getName();
+        String subjectDN = lastReceivedServerCertificates[0].getSubjectDN().getName();
+        // converting the values to lowercase is required cause the certificate is
+        // having attribute names in capital letters e.c the above newIssuerDN will be present
as CN=new_issuer_dn
+        assertEquals( "Expected the new certificate with the new issuer", newIssuerDN.toLowerCase(),
issuerDN.toLowerCase() );
+        assertEquals( "Expected the new certificate with the new subject", newSubjectDN.toLowerCase(),
subjectDN.toLowerCase() );
+    }
+
 }

Modified: directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/StartTlsIT.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/StartTlsIT.java?rev=805871&r1=805870&r2=805871&view=diff
==============================================================================
--- directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/StartTlsIT.java
(original)
+++ directory/apacheds/trunk/server-integ/src/test/java/org/apache/directory/server/ssl/StartTlsIT.java
Wed Aug 19 16:34:44 2009
@@ -26,6 +26,7 @@
 import java.security.KeyStore;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -52,8 +53,10 @@
 
 import org.apache.directory.server.core.CoreSession;
 import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.entry.ServerEntry;
 import org.apache.directory.server.core.integ.Level;
 import org.apache.directory.server.core.integ.annotations.CleanupLevel;
+import org.apache.directory.server.core.security.TlsKeyGenerator;
 import org.apache.directory.server.integ.ServerIntegrationUtils;
 import org.apache.directory.server.integ.SiRunner;
 import org.apache.directory.server.ldap.LdapServer;
@@ -389,4 +392,69 @@
             ctx.close();
         }
     }
+    
+    /**
+     * Test for DIRSERVER-1373.
+     */
+    @Test
+    public void testUpdateCertificate() throws Exception
+    {
+        // create a secure connection
+        Hashtable<String, String> env = new Hashtable<String, String>();
+        env.put( "java.naming.factory.initial", "com.sun.jndi.ldap.LdapCtxFactory" );
+        env.put( "java.naming.provider.url", "ldap://localhost:" + ldapServer.getPort() );
+        env.put( "java.naming.security.principal", "uid=admin,ou=system" );
+        env.put( "java.naming.security.credentials", "secret" );
+        env.put( "java.naming.security.authentication", "simple" );
+        LdapContext ctx = new InitialLdapContext( env, null );
+        StartTlsResponse tls = ( StartTlsResponse ) ctx.extendedOperation( new StartTlsRequest()
);
+        tls.setHostnameVerifier( new HostnameVerifier() {
+            public boolean verify( String hostname, SSLSession session )
+            {
+                return true;
+            } 
+        } );
+        tls.negotiate( BogusSSLContextFactory.getInstance( false ).getSocketFactory() );
+
+        // create a new certificate
+        String newIssuerDN = "cn=new_issuer_dn";
+        String newSubjectDN = "cn=new_subject_dn";
+        ServerEntry entry = ldapServer.getDirectoryService().getAdminSession().lookup(
+            new LdapDN( "uid=admin,ou=system" ) );
+        TlsKeyGenerator.addKeyPair( entry, newIssuerDN, newSubjectDN, "RSA" );
+
+        // now update the certificate (over the wire)
+        ModificationItem[] mods = new ModificationItem[3];
+        mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.PRIVATE_KEY_AT, entry.get( TlsKeyGenerator.PRIVATE_KEY_AT ).getBytes()
) );
+        mods[1] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.PUBLIC_KEY_AT, entry.get( TlsKeyGenerator.PUBLIC_KEY_AT ).getBytes()
) );
+        mods[2] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, new BasicAttribute(
+            TlsKeyGenerator.USER_CERTIFICATE_AT, entry.get( TlsKeyGenerator.USER_CERTIFICATE_AT
).getBytes() ) );
+        ctx.modifyAttributes( "uid=admin,ou=system", mods );
+        ctx.close();
+
+        ldapServer.reloadSslContext();
+        
+        // create a new secure connection
+        ctx = new InitialLdapContext( env, null );
+        tls = ( StartTlsResponse ) ctx.extendedOperation( new StartTlsRequest() );
+        tls.setHostnameVerifier( new HostnameVerifier() {
+            public boolean verify( String hostname, SSLSession session )
+            {
+                return true;
+            } 
+        } );
+        tls.negotiate( BogusSSLContextFactory.getInstance( false ).getSocketFactory() );
+
+        // check the received certificate, it must contain the updated server certificate
+        X509Certificate[] lastReceivedServerCertificates = BogusTrustManagerFactory.lastReceivedServerCertificates;
+        assertNotNull( lastReceivedServerCertificates );
+        assertEquals( 1, lastReceivedServerCertificates.length );
+        String issuerDN = lastReceivedServerCertificates[0].getIssuerDN().getName();
+        String subjectDN = lastReceivedServerCertificates[0].getSubjectDN().getName();
+        assertEquals( "Expected the new certificate with the new issuer", newIssuerDN.toLowerCase(),
issuerDN.toLowerCase() );
+        assertEquals( "Expected the new certificate with the new subject", newSubjectDN.toLowerCase(),
subjectDN.toLowerCase() );
+    }
+
 }



Mime
View raw message