Chapter 5. Authenticating To the Directory

Table of Contents
5.1. Simple Authentication
5.2. Start TLS & SSL Authentication
5.3. SASL Authentication

When your client application connects to the directory, the first operation to perform is a bind operation. The bind operation authenticates the client to the directory.

5.1. Simple Authentication

You perform simple authentication by binding with the distinguished name of a user's directory entry and the user's password. For this reason simple authentication over unsecure network connections should be done only in the lab. If your real end users are providing their passwords, your application must use simple authentication only if the network is secure.

To bind using Barbara Jensen's identity and simple authentication, for example, your application would provide the DN uid=bjensen,ou=People,dc=example,dc=com with the password hifalutin.

The directory stores the password value used for simple authentication in binary form on the userPassword attribute of the entry. In other words, for the purposes of your application the password is not a string, but instead an array of bytes. Typically the directory is further configured to store only hashed values of user passwords, rather than plain text versions. Thus even if someone managed to read the stored password values, they would still have to crack the hash in order to learn the actual passwords. When your application performing simple authentication sends the password value, the directory server therefore hashes the password value, and then compares the hashed result with the value of the userPassword on the user entry. If the values match, then the directory authenticates the user. Once the user has authenticated, the directory determines authorization for operations on the connection based on the users identity.

/**
 * Authenticate over LDAP.
 */
private static void connect()
{
  final LDAPConnectionFactory factory = new LDAPConnectionFactory(
    host, port);
  Connection connection = null;

  try
  {
    connection = factory.getConnection();
    connection.bind(bindDN, bindPassword.toCharArray());
    System.out.println("Authenticated as " + bindDN + ".");
  }
  catch (final ErrorResultException e)
  {
    System.err.println(e.getMessage());
    System.exit(e.getResult().getResultCode().intValue());
    return;
  }
  finally
  {
    if (connection != null) connection.close();
  }
}

If the password values do not match, a directory might nevertheless authenticate the client application. The LDAP specifications say that in this case, however, the directory authenticates the user as anonymous, therefore no doubt with fewer rights than the normal user, and surely fewer rights than an administrator.

For a complete example in context, see SimpleAuth.java, one of the OpenDJ LDAP SDK examples.

5.2. Start TLS & SSL Authentication

Simple authentication involves sending a user name and password to the directory server. To avoid sending the user name and password in the clear, you can use SSL or Start TLS.

For both SSL and Start TLS, you pass LDAP options to the connection factory in order to set an SSL context, and set whether to use Start TLS. The SSL context lets you set a trust manager to check server certificates, and also set a key manager to provide keys when the server needs to check your client certificates. In the simplest, not-so-secure case, you can set up a trust manager that trusts all certificates.

The following example is an excerpt from the OpenDJ LDAP SDK example, org.forgerock.opendj.examples.SimpleAuth.java.

private static LDAPOptions getTrustAllOptions()
  throws GeneralSecurityException
{
  LDAPOptions lo = new LDAPOptions();
  SSLContext sslContext = new SSLContextBuilder()
    .setTrustManager(TrustManagers.trustAll()).getSSLContext();
  lo.setSSLContext(sslContext);
  lo.setUseStartTLS(useStartTLS);
  return lo;
}

A more secure and extensive SSL context would include a trust manager using a trust store and trust manager methods to check server certificates. If you also want to be able to authenticate to the server using your client certificate, you would need a key manager.

The authentication over SSL or using Start TLS in the trust-all case is much like simple authentication over LDAP without connection-level security. The primary differences are that you pass the LDAPOptions to the LDAP connection factory, and that you handle the potential security exception involved in setting up the SSL context.

/**
 * Perform authentication over a secure connection, trusting all server
 * certificates.
 */
private static void trustAllConnect()
{
  Connection connection = null;

  try
  {
    final LDAPConnectionFactory factory =
        new LDAPConnectionFactory(host, port, getTrustAllOptions());
    connection = factory.getConnection();
    connection.bind(bindDN, bindPassword.toCharArray());
    System.out.println("Authenticated as " + bindDN + ".");
  }
  catch (final ErrorResultException e)
  {
    System.err.println(e.getMessage());
    System.exit(e.getResult().getResultCode().intValue());
    return;
  }
  catch (final GeneralSecurityException e)
  {
    System.err.println(e.getMessage());
    System.exit(ResultCode.CLIENT_SIDE_CONNECT_ERROR.intValue());
  }
  finally
  {
    if (connection != null)
      connection.close();
  }
}

For a complete example in context, see SimpleAuth.java, one of the OpenDJ LDAP SDK examples.

5.3. SASL Authentication

Simple Authentication and Security Layer (SASL) provides a way to use other mechanisms for authentication such as Kerberos or Digest authentication, or even to define your own authentication mechanism. The directory server likely advertises supported SASL mechanisms in the root DSE. The follow example shows how to search OpenDJ for supported SASL mechanisms.

$ ldapsearch
 --port 1389
 --bindDN "cn=Directory Manager"
 --bindPassword password
 --baseDN ""
 --searchScope base
 "(objectclass=*)" supportedSASLMechanisms
dn: 
supportedSASLMechanisms: PLAIN
supportedSASLMechanisms: EXTERNAL
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: CRAM-MD5

Notice that neither the Kerberos (GSSAPI SASL) nor the Anonymous mechanism is enabled by default, though OpenDJ implements both.

In order to use a SASL mechanism to bind, your program must set up a SASLBindRequest and pass that to the bind() method of the Connection.

This section shows an example using the SASL PLAIN mechanism, which takes either a DN or a user ID to authenticate, with an optional DN or user ID as the authorization ID that identifies the user who performs operations. The SASL PLAIN mechanism itself does not secure the connection, so the example uses StartTLS. The example is provided with the OpenDJ LDAP SDK examples in org.forgerock.opendj.examples.SASLAuth.java. The following excerpt shows the core of the bind process.

try
{
  final LDAPConnectionFactory factory =
      new LDAPConnectionFactory(host, port, getTrustAllOptions());
  connection = factory.getConnection();
  PlainSASLBindRequest request =
      Requests.newPlainSASLBindRequest(authcid, passwd.toCharArray())
      .setAuthorizationID(authzid);
  connection.bind(request);
  System.out.println("Authenticated as " + authcid + ".");
}

The implementation for getTrustAllOptions(), the same as in the example above, sets up Start TLS. When you run this example with both authorization and authentication IDs, authzid and authcid, set to u:bjensen and password hifalutin, the bind is successful, and the program reaches the final line of the try block.

Authenticated as u:bjensen.

Behind the scenes, OpenDJ has the SASL PLAIN mechanism configured by default to use the Exact Match Identity Mapper to look up user IDs as uid values. If you use another directory server, you might have to configure how it maps user IDs to user entries.

For a complete example in context, see SASLAuth.java, one of the OpenDJ LDAP SDK examples.