Authentication

Authentication against an LDAP follows this multi-step process:

  1. DN Resolution
  2. Password Validation
  3. Entry Resolution
// use a secure connection for authentication
ConnectionConfig connConfig = new ConnectionConfig("ldap://directory.ldaptive.org");
connConfig.setUseStartTLS(true);

// use a search dn resolver
SearchDnResolver dnResolver = new SearchDnResolver(new DefaultConnectionFactory(connConfig));
dnResolver.setBaseDn("ou=people,dc=ldaptive,dc=org");
dnResolver.setUserFilter("(uid={user})");

// perform a bind for password validation
BindAuthenticationHandler authHandler = new BindAuthenticationHandler(new DefaultConnectionFactory(connConfig));

Authenticator auth = new Authenticator(dnResolver, authHandler);
AuthenticationResponse response = auth.authenticate(
  new AuthenticationRequest("dfisher", new Credential("password"), new String[] {"mail", "sn"}));
if (response.getResult()) { // authentication succeeded
  LdapEntry entry = response.getLdapEntry(); // read mail and sn attributes

} else { // authentication failed
  String msg = response.getMessage(); // read the failure message
  ResponseControl[] ctls = response.getControls(); // read any response controls
}

DN Resolution

Authentication typically begins by gathering an identifier from the user that matches some attribute on their LDAP entry. The DN of the LDAP entry can then be resolved using that identifier. The interface for DN resolvers looks like:

public interface DnResolver
{
  String resolve(User user) throws LdapException;
}

Ldaptive provides the following DN resolution implementations:

SearchDnResolver / PooledSearchDnResolver

Resolves an entry DN by performing an LDAP search. This resolver has the following properties:

Name Default Value Description
baseDn ”” baseDN to search on
userFilter null search filter to execute; e.g. (mail={user})
userFilterArgs null search filter arguments
allowMultipleDns false whether to throw an exception if multiple entries are found with the search filter
subtreeSearch false whether a subtree search should be performed; by default a onelevel search is used

The {user} search filter argument is always assigned the user value from AuthenticationRequest#getUser(), so the userFilterArgs property only needs to be set when you specify custom arguments. Note that the SearchDnResolver will open and close a connection for every authentication.

If your directory does not allow anonymous access to the attribute used for DN resolution then you can configure a BindConnectionInitializer:

ConnectionConfig connConfig = new ConnectionConfig("ldap://directory.ldaptive.org");
connConfig.setUseStartTLS(true);
connConfig.setConnectionInitializer(
  new BindConnectionInitializer("cn=manager,ou=people,dc=ldaptive,dc=org", new Credential("password")));
SearchDnResolver dnResolver = new SearchDnResolver(new DefaultConnectionFactory(connConfig));

FormatDnResolver

Resolves an entry DN by using String#format(String, Object[]). This resolver is typically used when an entry DN can be formatted directly from the user identifier. For instance, entry DNs of the form uid=dfisher,ou=people,dc=ldaptive,dc=org could be formatted from uid=%s,ou=people,dc=ldaptive,dc=org. This resolver has the following properties:

Name Default Value Description
formatString null format of the DN
formatArgs null format arguments

The %1$s format argument is always assigned the user value from AuthenticationRequest#getUser(). So any arguments supplied in formatArgs will begin at %2$s.

NoOpDnResolver

Does not perform any resolution. The user value from AuthenticationRequest#getUser() is returned as the DN. Used by authentication mechanisms that do not leverage an entry DN, such as DIGEST-MD5.

AggregateDnResolver

Uses multiple DN resolvers to look up a user’s DN. Each DN resolver is invoked on a separate thread. If multiple DNs are allowed then the first one retrieved is returned. Note that you must use the AggregateDnResolver#AuthenticationHandler inner class with this implementation. The labels provided must link a single DN resolver to a single authentication handler.

// define two connection configs for the servers to aggregate
ConnectionConfig connConfig1 = new ConnectionConfig("ldap://directory1.ldaptive.org");
connConfig1.setUseStartTLS(true);
ConnectionConfig connConfig2 = new ConnectionConfig("ldap://directory2.ldaptive.org");
connConfig2.setUseStartTLS(true);

// use two search dn resolvers
SearchDnResolver dnResolver1 = new SearchDnResolver(new DefaultConnectionFactory(connConfig1));
dnResolver1.setBaseDn("ou=people,dc=ldaptive,dc=org");
dnResolver1.setUserFilter("(uid={user})");

SearchDnResolver dnResolver2 = new SearchDnResolver(new DefaultConnectionFactory(connConfig2));
dnResolver2.setBaseDn("ou=accounts,dc=ldaptive,dc=org");
dnResolver2.setUserFilter("(mail={user})");

final Map<String, DnResolver> resolvers = new HashMap<>();
resolvers.put("directory1", dnResolver1);
resolvers.put("directory2", dnResolver2);

final AggregateDnResolver resolver = new AggregateDnResolver(resolvers);

// use two bind authentication handlers
BindAuthenticationHandler authHandler1 = new BindAuthenticationHandler(new DefaultConnectionFactory(connConfig1));
BindAuthenticationHandler authHandler2 = new BindAuthenticationHandler(new DefaultConnectionFactory(connConfig2));
final Map<String, AuthenticationHandler> handlers = new HashMap<>();
handlers.put("directory1", authHandler1);
handlers.put("directory2", authHandler2);

final AggregateDnResolver.AuthenticationHandler handler = new AggregateDnResolver.AuthenticationHandler(handlers);

// create an authenticator that aggregates over both directories
Authenticator auth = new Authenticator(resolver, handler);

Use cases

Password Validation

Password validation is done by an AuthenticationHandler. It’s purpose is to use the entry DN and the credential to determine if authentication should succeed. The interface for authentication handlers looks like:

public interface AuthenticationHandler
{
  AuthenticationHandlerResponse authenticate(AuthenticationCriteria criteria) throws LdapException;
}

Ldaptive provides the following authentication handler implementations:

BindAuthenticationHandler / PooledBindAuthenticationHandler

Authenticates an entry DN by performing an LDAP bind operation with that DN and the credential. This is the most common method of authentication against an LDAP and should be used in most circumstances. Note that the BindAuthenticationHandler will open and close a connection for every authentication.

CompareAuthenticationHandler / PooledCompareAuthenticationHandler

Authenticates an entry DN by performing an LDAP compare operation on the userPassword attribute. This authentication handler should be used in cases where you do not have authorization to perform binds, but do have authorization to read the userPassword attribute. Note that the CompareAuthenticationHandler will open and close a connection for every authentication. This authentication handler has the following properties:

Name Default Value Description
passwordScheme SHA hash algorithm used by the LDAP for userPassword; Must be a valid Java MessageDigest algorithm.

Entry Resolution

The authentication process always returns an LDAP entry for the DN that attempted authentication. By default a new LdapEntry is simply created with the DN, no LDAP interaction occurs. However, you may wish to return some or all of the user’s LDAP attributes after authentication. The interface for entry resolvers looks like:

public interface EntryResolver
{
  LdapEntry resolve(AuthenticationCriteria criteria, AuthenticationHandlerResponse response) throws LdapException;
}

The connection supplied is the connection that authentication occurred on and the criteria is what was used to authenticate. The entry resolver is only invoked if authentication succeeds. Ldaptive provides the following entry resolver implementations:

SearchEntryResolver

Performs an object level search on the same connection that authentication occurred on and returns any requested attributes. This entry resolver has the following properties:

Name Default Value Description
returnAttributes null attributes to return from the search; null means return all attributes

NoOpEntryResolver

Returns a new LdapEntry that contains only the authenticated DN. This is the default entry resolver.

Response Processing

Authentication response handlers are an optional component of the authenticator which can be used to post process authentication responses. The interface for authentication response handlers looks like:

public interface AuthenticationResponseHandler
{
  void process(AuthenticationResponse response);
}

Potential use cases for authentication response handlers include:

See the account state documentation for examples on how response handlers can be leveraged with various password policy implementations.