You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2019/04/17 07:39:36 UTC

[directory-ldap-api] branch 1.0 updated: o Fix the LdapNetworConnection so that it works with MINA 2.0.21 (no reason to switch to 2.1.x) o Added a test for SSL (but it requires a running LDAP server beside. Use Studio...)

This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch 1.0
in repository https://gitbox.apache.org/repos/asf/directory-ldap-api.git


The following commit(s) were added to refs/heads/1.0 by this push:
     new 3abbd46  o Fix the LdapNetworConnection so that it works with MINA 2.0.21 (no reason to switch to 2.1.x) o Added a test for SSL (but it requires a running LDAP server beside. Use Studio...)
3abbd46 is described below

commit 3abbd46e7ba821e8c7124426965a8db33d2ca2c1
Author: emmanuel lecharny <el...@apache.org>
AuthorDate: Wed Apr 17 09:39:23 2019 +0200

    o Fix the LdapNetworConnection so that it works with MINA 2.0.21 (no
    reason to switch to 2.1.x)
    o Added a test for SSL (but it requires a running LDAP server beside.
    Use Studio...)
---
 .../ldap/client/api/LdapNetworkConnection.java     |  67 +++----
 .../ldap/client/api/LdapSSLConnectionTest.java     | 222 +++++++++++++++++++++
 2 files changed, 247 insertions(+), 42 deletions(-)

diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
index 6c2536d..e7a3214 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
@@ -165,10 +165,8 @@ import org.apache.mina.core.future.IoFutureListener;
 import org.apache.mina.core.future.WriteFuture;
 import org.apache.mina.core.service.IoConnector;
 import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.FilterEvent;
 import org.apache.mina.filter.codec.ProtocolCodecFilter;
 import org.apache.mina.filter.codec.ProtocolEncoderException;
-import org.apache.mina.filter.ssl.SslEvent;
 import org.apache.mina.filter.ssl.SslFilter;
 import org.apache.mina.transport.socket.SocketSessionConfig;
 import org.apache.mina.transport.socket.nio.NioSocketConnector;
@@ -241,9 +239,6 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
     /** The exception stored in the session if we've got one */
     private static final String EXCEPTION_KEY = "sessionException";
     
-    /** A future used to block any action until the handhake is completed */
-    private HandshakeFuture handshakeFuture;
-
     // ~~~~~~~~~~~~~~~~~ common error messages ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
     static final String TIME_OUT_ERROR = "TimeOut occurred";
@@ -669,25 +664,6 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
         {
             connectionFuture = connector.connect( address );
 
-            if ( config.isUseSsl() )
-            {
-                try
-                {
-                    boolean isSecured = handshakeFuture.get( timeout, TimeUnit.MILLISECONDS );
-                
-                    if ( !isSecured )
-                    {
-                        throw new LdapOperationException( ResultCodeEnum.OTHER, I18n.err( I18n.ERR_4100_TLS_HANDSHAKE_ERROR ) );
-                    }
-                }
-                catch ( Exception e )
-                {
-                    String msg = "Failed to initialize the SSL context";
-                    LOG.error( msg, e );
-                    throw new LdapException( msg, e );
-                }
-            }
-
             boolean result = false;
 
             // Wait until it's established
@@ -2047,6 +2023,27 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
     public void messageReceived( IoSession session, Object message ) throws Exception
     {
         // Feed the response and store it into the session
+        if ( message instanceof SslFilter.SslFilterMessage )
+        {
+            // This is a SSL message telling if the session has been secured or not
+            HandshakeFuture handshakeFuture = ( HandshakeFuture ) session.getAttribute( "HANDSHAKE_FUTURE" );
+
+            if ( message == SslFilter.SESSION_SECURED )
+            {
+                // SECURED
+                handshakeFuture.secured();
+            }
+            else
+            {
+                // UNSECURED
+                handshakeFuture.cancel();
+            }
+
+            session.removeAttribute( "HANDSHAKE_FUTURE" );
+            
+            return;
+        }
+
         Message response = ( Message ) message;
         LOG.debug( "-------> {} Message received <-------", response );
         int messageId = response.getMessageId();
@@ -3928,20 +3925,6 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
      * {@inheritDoc}
      */
     @Override
-    public void event( IoSession session, FilterEvent event ) throws Exception 
-    {
-        // Check if it's a SSLevent 
-        if ( ( event instanceof SslEvent ) && ( ( SslEvent ) event == SslEvent.SECURED ) )
-        {
-            handshakeFuture.secured();
-        }
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public void sessionClosed( IoSession session ) throws Exception
     {
         // no need to handle if this session was closed by the user
@@ -4079,9 +4062,6 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
                     { "TLSv1", "TLSv1.1", "TLSv1.2" } );
             }
 
-            // for LDAPS/startTLS
-            handshakeFuture = new HandshakeFuture();
-
             if ( ( ldapSession == null ) || !connected.get() )
             {
                 connector.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
@@ -4089,8 +4069,11 @@ public class LdapNetworkConnection extends AbstractLdapConnection implements Lda
             else
             // for StartTLS
             {
-                ldapSession.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
+                HandshakeFuture handshakeFuture = new HandshakeFuture();
 
+                ldapSession.setAttribute( SslFilter.USE_NOTIFICATION, Boolean.TRUE );
+                ldapSession.setAttribute( "HANDSHAKE_FUTURE", handshakeFuture );
+                ldapSession.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
                 boolean isSecured = handshakeFuture.get( timeout, TimeUnit.MILLISECONDS );
                 
                 if ( !isSecured )
diff --git a/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapSSLConnectionTest.java b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapSSLConnectionTest.java
new file mode 100644
index 0000000..ecfe50a
--- /dev/null
+++ b/ldap/client/api/src/test/java/org/apache/directory/ldap/client/api/LdapSSLConnectionTest.java
@@ -0,0 +1,222 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.ldap.client.api;
+
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.directory.api.ldap.codec.api.SchemaBinaryAttributeDetector;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.util.Network;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapConnectionConfig;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.directory.ldap.client.api.NoVerificationTrustManager;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+/**
+ * Test the LdapConnection class by enabling SSL and StartTLS one after the other
+ * (using both in the same test class saves the time required to start/stop another server for StartTLS)
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+
+public class LdapSSLConnectionTest
+{
+    private LdapConnectionConfig sslConfig;
+
+    private LdapConnectionConfig tlsConfig;
+
+
+    @Before
+    public void setup() throws Exception
+    {
+        sslConfig = new LdapConnectionConfig();
+        sslConfig.setLdapHost( Network.LOOPBACK_HOSTNAME );
+        sslConfig.setUseSsl( true );
+        sslConfig.setLdapPort( 10636 );
+        sslConfig.setTrustManagers( new NoVerificationTrustManager() );
+        sslConfig.setBinaryAttributeDetector( new SchemaBinaryAttributeDetector( null ) );
+
+        tlsConfig = new LdapConnectionConfig();
+        tlsConfig.setLdapHost( Network.LOOPBACK_HOSTNAME );
+        tlsConfig.setLdapPort( 10389 );
+        tlsConfig.setTrustManagers( new NoVerificationTrustManager() );
+        tlsConfig.setBinaryAttributeDetector( new SchemaBinaryAttributeDetector( null ) );
+    }
+
+
+    /**
+     * Test a successful bind request
+     *
+     * @throws IOException
+     */
+    @Test
+    @Ignore
+    public void testBindRequestSSLConfig() throws Exception
+    {
+        try ( LdapNetworkConnection connection = new LdapNetworkConnection( sslConfig ) )
+        {
+            connection.bind( "uid=admin,ou=system", "secret" );
+
+            assertTrue( connection.getConfig().isUseSsl() );
+            assertTrue( connection.isAuthenticated() );
+            assertTrue( connection.isSecured() );
+        }
+    }
+
+
+    /**
+     * Test a successful bind request
+     *
+     * @throws IOException
+     */
+    @Test
+    @Ignore
+    public void testBindRequestSSLAuto() throws Exception
+    {
+        sslConfig.setTrustManagers( new X509TrustManager[] { new NoVerificationTrustManager() } );
+
+        try ( LdapNetworkConnection connection = 
+            new LdapNetworkConnection( sslConfig ) )
+        {
+            connection.bind( "uid=admin,ou=system", "secret" );
+            assertTrue( connection.getConfig().isUseSsl() );
+
+            assertTrue( connection.isAuthenticated() );
+            assertTrue( connection.isSecured() );
+        }
+    }
+
+
+    @Test
+    @Ignore
+    public void testGetSupportedControls() throws Exception
+    {
+        try ( LdapConnection connection = new LdapNetworkConnection( sslConfig ) )
+        {    
+            Dn dn = new Dn( "uid=admin,ou=system" );
+            connection.bind( dn.getName(), "secret" );
+    
+            List<String> controlList = connection.getSupportedControls();
+            assertNotNull( controlList );
+            assertFalse( controlList.isEmpty() );
+        }
+    }
+
+
+    /**
+     * Test a successful bind request after setting up TLS
+     *
+     * @throws IOException
+     */
+    @Test
+    @Ignore
+    public void testStartTLSBindRequest() throws Exception
+    {
+        try ( LdapNetworkConnection connection = new LdapNetworkConnection( tlsConfig ) )
+        {
+            tlsConfig.setUseTls( true );
+            connection.connect();
+
+            connection.bind( "uid=admin,ou=system", "secret" );
+            assertTrue( connection.isAuthenticated() );
+
+            // try multiple binds with startTLS DIRAPI-173
+            connection.bind( "uid=admin,ou=system", "secret" );
+            assertTrue( connection.isAuthenticated() );
+            
+            connection.bind( "uid=admin,ou=system", "secret" );
+            assertTrue( connection.isAuthenticated() );
+            assertTrue( connection.isSecured() );
+
+            connection.unBind();
+        }
+    }
+
+
+    /**
+     * Test a request before setting up TLS
+     *
+     * @throws IOException
+     */
+    @Test
+    @Ignore
+    public void testStartTLSAfterBind() throws Exception
+    {
+        tlsConfig.setTrustManagers( new X509TrustManager[] { new NoVerificationTrustManager() } );
+
+        try ( LdapNetworkConnection connection = 
+            new LdapNetworkConnection( tlsConfig ) )
+        {
+            connection.connect();
+
+            connection.bind( "uid=admin,ou=system", "secret" );
+            assertFalse( connection.isSecured() );
+
+            Entry rootDse = connection.getRootDse( "*", "+" );
+            
+            assertNotNull( rootDse );
+
+            // startTLS
+            connection.startTls();
+            
+            // try multiple binds with startTLS DIRAPI-173
+            assertTrue( connection.isSecured() );
+
+            Entry admin = connection.lookup( "uid=admin,ou=system" );
+
+            assertNotNull( admin );
+            assertEquals( "uid=admin,ou=system", admin.getDn().getName() );
+
+            connection.unBind();
+        }
+    }
+
+
+    @Test
+    @Ignore
+    public void testGetSupportedControlsWithStartTLS() throws Exception
+    {
+        try ( LdapNetworkConnection connection = new LdapNetworkConnection( tlsConfig ) )
+        {
+            tlsConfig.setUseTls( true );
+            connection.connect();
+    
+            Dn dn = new Dn( "uid=admin,ou=system" );
+            connection.bind( dn.getName(), "secret" );
+    
+            List<String> controlList = connection.getSupportedControls();
+            assertNotNull( controlList );
+            assertFalse( controlList.isEmpty() );
+        }
+    }
+}