User Authentication using Spring LDAP

This section covers user authentication with Spring LDAP. It contains the following topics:

Basic Authentication

While the core functionality of the ContextSource is to provide DirContext instances for use by LdapClient and LdapTemplate, you can also use it for authenticating users against an LDAP server. The getContext(principal, credentials) method of ContextSource does exactly that. It constructs a DirContext instance according to the ContextSource configuration and authenticates the context by using the supplied principal and credentials. A custom authenticate method could look like the following example:

public boolean authenticate(String userDn, String credentials) {
  DirContext ctx = null;
  try {
    ctx = contextSource.getContext(userDn, credentials);
    return true;
  } catch (Exception e) {
    // Context creation failed - authentication did not succeed
    logger.error("Login failed", e);
    return false;
  } finally {
    // It is imperative that the created DirContext instance is always closed
    LdapUtils.closeContext(ctx);
  }
}

The userDn supplied to the authenticate method needs to be the full DN of the user to authenticate (regardless of the base setting on the ContextSource). You typically need to perform an LDAP search based on (for example) the user name to get this DN. The following example shows how to do so:

private String getDnForUser(String uid) {
  List<String> result = ldapClient.search()
      .query(query().where("uid").is(uid))
      .toList((Object ctx) -> ((DirContextOperations) ctx).getNameInNamespace());

  if(result.size() != 1) {
    throw new RuntimeException("User not found or not unique");
  }

  return result.get(0);
}

There are some drawbacks to this approach. You are forced to concern yourself with the DN of the user, you can search only for the user’s uid, and the search always starts at the root of the tree (the empty path). A more flexible method would let you specify the search base, the search filter, and the credentials. Spring LDAP includes an authenticate method in LdapClient that provides this functionality.

When you use this method, authentication becomes as simple as follows:

Example 1. Authenticating a user using Spring LDAP
ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute();
As described in the Performing Operations on the Authenticated Context, some setups may require you to perform additional operations to get actual authentication to occur. See Performing Operations on the Authenticated Context for details.
Do not write your own custom authenticate methods. Use the ones provided in Spring LDAP.

Performing Operations on the Authenticated Context

Some authentication schemes and LDAP servers require some operation to be performed on the created DirContext instance for the actual authentication to occur. You should test and make sure how your server setup and authentication schemes behave. Failure to do so might result in users being admitted into your system regardless of the supplied DN and credentials. The following example shows a naïve implementation of an authenticate method where a hard-coded lookup operation is performed on the authenticated context:

public boolean myAuthenticate(String userDn, String credentials) {
  DirContext ctx = null;
  try {
    ctx = contextSource.getContext(userDn, credentials);
    // Take care here - if a base was specified on the ContextSource
    // that needs to be removed from the user DN for the lookup to succeed.
    ctx.lookup(userDn);
    return true;
  } catch (Exception e) {
    // Context creation failed - authentication did not succeed
    logger.error("Login failed", e);
    return false;
  } finally {
    // It is imperative that the created DirContext instance is always closed
    LdapUtils.closeContext(ctx);
  }
}

It would be better if the operation could be provided as an implementation of a callback interface, rather than limiting the operation to always be a lookup. Spring LDAP includes the AuthenticatedLdapEntryContextMapper callback interface and a corresponding authenticate method.

This method lets any operation be performed on the authenticated context, as follows:

Example 2. Performing an LDAP operation on the authenticated context using Spring LDAP
AuthenticatedLdapEntryContextMapper<DirContextOperations> mapper = new AuthenticatedLdapEntryContextMapper<DirContextOperations>() {
  public DirContextOperations mapWithContext(DirContext ctx, LdapEntryIdentification ldapEntryIdentification) {
    try {
      return (DirContextOperations) ctx.lookup(ldapEntryIdentification.getRelativeName());
    }
    catch (NamingException e) {
      throw new RuntimeException("Failed to lookup " + ldapEntryIdentification.getRelativeName(), e);
    }
  }
};

ldapClient.authenticate().query(query().where("uid").is("john.doe")).password("secret").execute(mapper);

Obsolete Authentication Methods

In addition to the authenticate methods described in the preceding sections, you can use a number of deprecated methods for authentication. While these work fine, we recommend using the LdapQuery methods instead.

Using Spring Security

While the approach described in the preceding sections may be sufficient for simple authentication scenarios, requirements in this area commonly expand rapidly. A multitude of aspects apply, including authentication, authorization, web integration, user context management, and others. If you suspect that the requirements might expand beyond just simple authentication, you should definitely consider using Spring Security for your security purposes instead. It is a full-featured, mature security framework that addresses the aforementioned aspects as well as several others.