5.1 - LDAPS

LDAP supports SSL, it’s called LDAPS, and it uses a dedicated port. As of today, and since 2000, LDAPS is deprecated and StartTLS should be used.

That being said, many servers accept LDAPS, and the Apache LDAP API supports it.

How does it work ?

The SSL protocol ensures that data is transmitted encrypted, and guarantees that the data received is valid. Noone can capture this data and read it, assuming the ciphers used are of sufficient strength.

With SSL, a dialog between the client and the server occurs, and when both agree on the particular cipher to use, then all subsequent data is encrypted. This dialog may include a mutual validation of their X.509 certificates.

Protocols

There are many version that can be used, but the idea is to use the most recent one, if the server supports it. In any case, as we depend on Java, we are also limited by the supported version on the client side. Here are all of the existing versions, and their statuses:

SSLversion Java 7 Client Java 7 Server Java 8 Client Java 8 Server
2.0 N/A N/A N/A N/A
3.0 Disabled Disabled N/A N/A
3.1 (aka TLSv1) Enabled Enabled Enabled Enabled
3.2 (aka TLSv1.1 Disabled Enabled Enabled Enabled
3.3 (aka TLSv1.2) Disabled Enabled Enabled Enabled

(Disabled means it’s not active by default, and so must be activated explicitly).

The default is Java will choose the best fit, assuming that it always starts with the newest version (TLSv1.2).

Still, you can enforce the version used – if needed.

A quick primer

Here is all that is needed to get LDAPS connections established with a server :

    try ( LdapConnection connection = new LdapNetworkConnection( "server-name", 636, true ) )
    {
        connection.bind( "uid=admin,ou=system", "secret" );

        assertTrue( connection.isAuthenticated() );
    }

It’s as simple as that! The 636 port is the default LDAPS port for standard LDAP servers, when running as root, and for ApacheDS you must pick 10636. The true flag is set to secure the connection. You don’t need to close the connection, it will be done automatically upon exiting the try{…} block.

By default, the selected protocol is TLS, and the server’s certificate is not verified.

A more sophisticated sample

It’s possible to have more control on the SSL configuration, and specifically to provide a specific TrustManager :

    try ( LdapConnection connection = new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, getLdapServer().getPortSSL(), 
            new NoVerificationTrustManager() ) )
    {
        connection.bind( "uid=admin,ou=system", "secret" );
        
        assertTrue( ((LdapNetworkConnection)connection).getConfig().isUseSsl() );
        assertTrue( connection.isAuthenticated() );
    }

Here, we use the NoVerificationTrustManager class, but you may define your own implementation of it. The Fortress project uses this class.

Using a configuration

One step further : you can define a dedicated configuration that is passed to the constructor. Many parameters can be defined:

  • the enabled cipher suites: a list of ciphers that may be used (like “TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384”, etc)
  • the enabled protocols: a list of protocals that may be used ( “SSLv3”, “TLS”, “TLSv1”, “TLSv1.1”, “TLSv1.2”)
  • the KeyManager instances
  • the SecureRandom instance
  • the SSL protocol to use: one of the enabled protocols
  • the TrustManager instances

All these parameters are configured using the LdapConnectionConfig class :

    LdapConnectionConfig sslConfig = new LdapConnectionConfig();
    sslConfig.setLdapHost( Network.LOOPBACK_HOSTNAME );
    sslConfig.setUseSsl( true );
    sslConfig.setLdapPort( getLdapServer().getPortSSL() );
    sslConfig.setTrustManagers( new NoVerificationTrustManager() );

    try ( LdapConnection connection = new LdapNetworkConnection( sslConfig ) )
    {
        connection.bind( "uid=admin,ou=system", "secret" );
        
        assertTrue( ((LdapNetworkConnection)connection).getConfig().isUseSsl() );
        assertTrue( connection.isAuthenticated() );
    }

LDAPS or startTLS ?

The important point to understand with LDAPS is that every request being exchanged between the client and the server is encrypted, because its underlying transport is encrypted. That means you can’t start communicating with the LDAP server before the connection is secured.

It has a few drawbacks:

  • first of all, it has an added CPU cost, as everything has to be encrypted and decrypted.
  • second, it requires a dedicated port, thus some specific routing rules (firewall, load balancers, etc)
  • third, it’s a all of nothing choice. If you want to return to a non-encrypted communication, you must use another connection.

This is the why the startTLS extended operation should be used instead.