LDAPAuthnConfiguration

The Shibboleth IdP V3 software has reached its End of Life and is no longer supported. This documentation is available for historical purposes only. See the IDP4 wiki space for current documentation on the supported version.

LDAPAuthnConfiguration

Current File(s): conf/authn/ldap-authn-config.xml

Format: Native Spring

V2 Legacy File(s): conf/handler.xml, conf/login.config

Overview

This back-end for the password authentication login flow uses native LDAP libraries for password-based authentication instead of using a JAAS module. The primary advantages are slightly better performance and more control over the process, such as the ability to extract detailed account status information from the directory during a login.

General Configuration

Configuring LDAP as a back-end requires that the right import is active in authn/password-authn-config.xml:

Import in authn/password-authn-config.xml
<import resource="ldap-authn-config.xml" />

The other imports must be commented or removed.

A large number of beans are defined in authn/ldap-authn-config.xml to configure this back-end, but in most cases the properties in ldap.properties can do most of the work needed. The beans can be used for very advanced cases where a higher degree of control is required.

A bean alias is also defined that instantiates the LDAP back-end action as the "ValidateUsernamePassword" step of the web flow. This must not be changed.

Basic Configuration

Authenticator Configuration

The idp.authn.LDAP.authenticator property controls the workflow for how authentication occurs against the LDAP directory:

anonSearchAuthenticator

Performs an anonymous search for the user's DN

bindSearchAuthenticator

Binds as a configured DN then searches for the user's DN

directAuthenticator

User DNs are of a known format. i.e. CN=user_name,ou=accounts,dc=domain,dc=edu. No DN search is performed.

adAuthenticator

Configuration that leverages the AD specific @domain.com format. No DN search is performed since AD supports binding directly with that user name.

Depending on the choice above, various other properties must be set (see the reference section below).

Connection Configuration

Use the following properties to configure basic connection information for the LDAP directory:

  • idp.authn.LDAP.ldapURL

  • idp.authn.LDAP.useStartTLS

  • idp.authn.LDAP.useSSL

  • idp.authn.LDAP.connectTimeout

A connection pool is used, and there are several properties used to configure pool behavior (see the reference below).

SSL Configuration

If StartTLS or SSL are used, a source of trust anchors must be configured to control certificate validation, using the idp.authn.LDAP.sslConfig property:

certificateTrust

Uses the idp.authn.LDAP.trustCertificates property to load a resource containing the trust anchors (such as a file of PEM-format certificates)

keyStoreTrust

Uses the idp.authn.LDAP.trustStore property to load a keystore containing the trust anchors

jvmTrust

Uses the default JVM trust anchors (the JVM-wide "cacerts" file)

Advanced Configuration

Use authn/ldap-authn-config.xml to perform advanced configuration. The beans in this file correspond to properties of the Ldaptive authentication interface (see http://www.ldaptive.org/docs/guide/authentication). If you want to completely alter the LDAP objects used, you may want to consider copying the file to create your own version, and modify the beans used.

Reference

Beans

Some of the most important beans defined in authn/ldap-authn-config.xml follow.

Many other beans are defined in the file subordinate to the beans below. You are free to modify them as you see fit. Only the first two beans below are actually used by the login flow; the rest are injected into the shibboleth.authn.LDAP.authenticator bean to make up its content.

Bean ID

Type

Default

Function

Bean ID

Type

Default

Function

shibboleth.authn.LDAP.authenticator

org.ldaptive.auth.Authenticator

 

Must be set to a bean of the appropriate type to configure the LDAP authentication library, normally a property-controlled alias for one of: anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, or adAuthenticator

shibboleth.authn.LDAP.returnAttributes

java.util.Collection<String>

 

The collection of attribute names to return in the LDAP operation, normally set via property

shibboleth.X509ResourceCredentialConfig

Resource path

 

A parent bean for supplying Ldaptive CredentialConfig instances using Spring resources containing X.509 trust anchors

shibboleth.KeystoreResourceCredentialConfig

Resource path

 

A parent bean for supplying Ldaptive CredentialConfig instances using Spring resources containing a Java keystore

sslConfig

org.ldaptive.ssl.SslConfig

 

Must be set to a bean of the appropriate type to configure the TLS trust source, normally a property-controlled alias for one of jvmTrust, certificateTrust, keystoreTrust

Properties

A number of properties are found in ldap.properties to configure LDAP authentication. Most of the time, this is sufficient to deal with most configurations without having to delve into modifying any beans.

Property

Type

Default

Function

Property

Type

Default

Function

idp.authn.LDAP.authenticator

Enumeration

anonSearchAuthenticator

Controls the workflow for how authentication occurs against the LDAP, one of: anonSearchAuthenticator, bindSearchAuthenticator, directAuthenticator, adAuthenticator

idp.authn.LDAP.ldapURL

LDAP URI

 

Connection URI for LDAP directory

idp.authn.LDAP.useStartTLS

Boolean

true

Whether StartTLS should be used after connecting with LDAP alone

idp.authn.LDAP.useSSL

Boolean

false

Whether SSL should be used directly

idp.authn.LDAP.connectTimeout

Integer

3000 (PT3S) 3.3

Connection timeout in milliseconds

idp.authn.LDAP.responseTimeout 3.3

Duration

PT3S

 

idp.authn.LDAP.sslConfig

Enumeration

certificateTrust

How to establish trust in the server's TLS certificate, one of: jvmTrust, certificateTrust, or keyStoreTrust

idp.authn.LDAP.trustCertificates

Resource path

 

A resource to load trust anchors from, usually a local file in %{idp.home}/credentials

idp.authn.LDAP.trustStore

Resource path

 

A resource to load a Java keystore containing trust anchors, usually a local file in %{idp.home}/credentials

idp.authn.LDAP.returnAttributes

Comma-sep'd Strings

 

List of attributes to request during authentication

idp.authn.LDAP.baseDN

String

 

Base DN to search against, used by anonSearchAuthenticator, bindSearchAuthenticator

idp.authn.LDAP.subtreeSearch

Boolean

false

Whether to search recursively, used by anonSearchAuthenticator, bindSearchAuthenticator

idp.authn.LDAP.userFilter

String

 

LDAP search filter, used by anonSearchAuthenticator, bindSearchAuthenticator

idp.authn.LDAP.bindDN

String

 

DN to bind with during search, used by bindSearchAuthenticator

idp.authn.LDAP.bindDNCredential

String

 

Password to bind with during search, used by bindSearchAuthenticator

idp.authn.LDAP.dnFormat

String

 

A formatting string to generate the user DNs to authenticate, used by directAuthenticator, adAuthenticator

idp.pool.LDAP.minSize

Integer

3

Minimum LDAP connection pool size

idp.pool.LDAP.maxSize

Integer

10

Maximum LDAP connection pool size

idp.pool.LDAP.validateOnCheckout

Boolean

false

Whether to validate connections when checking them out of the pool

idp.pool.LDAP.validatePeriodically

Boolean

true

Whether to validate connections in the background

idp.pool.LDAP.validatePeriod

Integer

300 (PT5M) 3.3

Interval in seconds between validation, if idp.pool.LDAP.validatePeriodically is true

idp.pool.LDAP.prunePeriod

Integer

300 (PT5M) 3.3

Interval in seconds between looking for idle connections to reduce the pool back to its minimum size

idp.pool.LDAP.idleTime

Integer

600 (PT10M) 3.3

Time in seconds that connections must be idle to be eligible for pruning

idp.pool.LDAP.blockWaitTime

Integer

3000 (PT3S) 3.3

Time in milliseconds to wait for a free connection in the pool

idp.pool.LDAP.failFastInitialize

Boolean

false

Whether to fail initialization of the components using the LDAP connection pool if the pool can't be established, or treat as a connection failure later

Attribute Retrieval

LDAP attributes are returned as part of the authentication process and exposed in the LDAPResponseContext.

Property

Value

Result

Property

Value

Result

idp.authn.LDAP.returnAttributes

uid,

eduPersonAffiliation

Returns the uid and

eduPersonAffiliation attributes.

idp.authn.LDAP.returnAttributes

*

Returns all user attributes on the entry.

idp.authn.LDAP.returnAttributes

*,+

Returns all user and operational attributes on the entry.

idp.authn.LDAP.returnAttributes

1.1

No attribute returned. No search performed.

 

By default, attributes will be searched for using the same connection the user authenticated on. Therefore the user must have read on any attributes for those to be returned. If you need access to attributes that user does not have read access to, then you must configure a connection pool that is authorized to read. The following configuration demonstrates how to add a new connection pool for that purpose.

ldap-authn-config.xml
<!-- Modify the authenticator to use the entry resolver --> <bean name="anonSearchAuthenticator" class="org.ldaptive.auth.Authenticator" p:entryResolver-ref="bindSearchEntryResolver"> ...   <!-- Add an entry resolver to read attributes --> <bean id="bindSearchEntryResolver" class="org.ldaptive.auth.PooledSearchEntryResolver" p:connectionFactory-ref="entryResolverPooledConnectionFactory" /> <bean id="entryResolverPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="entryResolverConnectionPool" /> <bean id="entryResolverConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="entryResolverConnectionFactory" p:name="entry-resolver-pool" /> <bean id="entryResolverConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="entryResolverConnectionConfig" /> <bean id="entryResolverConnectionConfig" parent="connectionConfig" p:connectionInitializer-ref="entryResolverConnectionInitializer" /> <bean id="entryResolverConnectionInitializer" class="org.ldaptive.BindConnectionInitializer" p:bindDn="%{idp.authn.LDAP.entryResolver.bindDN}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential"> <constructor-arg value="%{idp.authn.LDAP.entryResolver.bindDNCredential}" /> </bean> </property> </bean>

Add the idp.authn.LDAP.entryResolver.bindDN and idp.authn.LDAP.entryResolver.bindDNCredential properties to conf/ldap.properties to complete the configuration.

Note: if you're using the bindSearchAuthenticator and those credentials can be reused for entry resolution, then this configuration can be shortened by wiring the bindPooledConnectionFactory to the entry resolver.

DN Resolution

Single Directory with multiple branches

Extensible Matching

If your directory supports extensible matching, this is easiest way to find users that are distributed over multiple branches.

Property

Value

Result

Property

Value

Result

idp.authn.LDAP.userFilter

(&(|(ou:dn:=people)(ou:dn:=guests))(uid={user}))

Returns the entry that matches uid on either the people or guests branch.

idp.authn.LDAP.baseDN

dc=example,dc=org

The branch containing both ou=people and ou=guests.

idp.authn.LDAP.subtreeSearch

true

Enable subtree searching on the dc=example,dc=org branch.

Aggregate DN Resolver

This authenticator combines the results of multiple DN resolvers.

ldap-authn-config.xml
<bean name="aggregateAuthenticator" class="org.ldaptive.auth.Authenticator"> <constructor-arg index="0" ref="aggregateDnResolver" /> <constructor-arg index="1" ref="aggregateAuthHandler" /> </bean> <bean id="aggregateDnResolver" class="org.ldaptive.auth.AggregateDnResolver"> <constructor-arg index="0" ref="dnResolvers" /> </bean> <bean id="aggregateAuthHandler" class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandler" p:authenticationHandlers-ref="authHandlers" /> <util:map id="dnResolvers"> <entry key="filter1" value-ref="dnResolver1" /> <entry key="filter2" value-ref="dnResolver2" /> </util:map> <!-- Define two DN resolvers that use anonymous search against the same directory --> <bean id="dnResolver1" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN1}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="%{idp.authn.LDAP.userFilter1}" p:connectionFactory-ref="anonSearchPooledConnectionFactory" /> <bean id="dnResolver2" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN2}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="%{idp.authn.LDAP.userFilter2}" p:connectionFactory-ref="anonSearchPooledConnectionFactory" /> <!-- Use the same authentication handler for both DN resolvers --> <util:map id="authHandlers"> <entry key="filter1" value-ref="authHandler" /> <entry key="filter2" value-ref="authHandler" /> </util:map>

Add the idp.authn.LDAP.baseDN[12] and idp.authn.LDAP.userFilter[12] properties to conf/ldap.properties to complete the configuration. The key values used in dnResolvers and authHandlers can be anything, but must tie a single DN resolver to a single auth handler. By default an error will occur if more than (1) DN is resolved.

Multiple Directories

Aggregate DN Resolver

This authenticator combines the results of multiple DN resolvers that connect to multiple directories.

ldap-authn-config.xml
<bean name="aggregateAuthenticator" class="org.ldaptive.auth.Authenticator"> <constructor-arg index="0" ref="aggregateDnResolver" /> <constructor-arg index="1" ref="aggregateAuthHandler" /> </bean> <bean id="aggregateDnResolver" class="org.ldaptive.auth.AggregateDnResolver"> <constructor-arg index="0" ref="dnResolvers" /> </bean> <bean id="aggregateAuthHandler" class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandler" p:authenticationHandlers-ref="authHandlers" /> <util:map id="dnResolvers"> <entry key="directory1" value-ref="dnResolver1" /> <entry key="directory2" value-ref="dnResolver2" /> </util:map> <util:map id="authHandlers"> <entry key="directory1" value-ref="authHandler1" /> <entry key="directory2" value-ref="authHandler2" /> </util:map> <!-- define DN resolvers and authentication handlers for each directory... -->
<!-- Properties: - idp.authn.LDAP.authenticator = aggregateAuthenticator - idp.authn.LDAP.ldapURL1 - idp.authn.LDAP.ldapURL2 - idp.authn.LDAP.baseDN1 - idp.authn.LDAP.baseDN2 - idp.authn.LDAP.userFilter1 - idp.authn.LDAP.userFilter2 - idp.authn.LDAP.bindDN1 - idp.authn.LDAP.bindDN2 - idp.authn.LDAP.bindDNCredential1 - idp.authn.LDAP.bindDNCredential2 --> <bean id="aggregateAuthenticator" class="org.ldaptive.auth.Authenticator" c:resolver-ref="aggregateDnResolver" c:handler-ref="aggregateAuthHandler" /> <!-- Aggregate DN resolution --> <bean id="aggregateDnResolver" class="org.ldaptive.auth.AggregateDnResolver" c:resolvers-ref="dnResolvers" p:allowMultipleDns="true" /> <util:map id="dnResolvers"> <entry key="directory1" value-ref="bindSearchDnResolver1" /> <entry key="directory2" value-ref="bindSearchDnResolver2" /> </util:map> <!-- DN resolver 1 --> <bean id="bindSearchDnResolver1" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="#{'%{idp.authn.LDAP.baseDN1:undefined}'.trim()}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="#{'%{idp.authn.LDAP.userFilter1:undefined}'.trim()}" p:connectionFactory-ref="bindSearchPooledConnectionFactory1" /> <bean id="bindSearchPooledConnectionFactory1" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindSearchConnectionPool1" /> <bean id="bindSearchConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="bindSearchConnectionFactory1" p:name="search-pool1" /> <bean id="bindSearchConnectionFactory1" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindSearchConnectionConfig1" /> <bean id="bindSearchConnectionConfig1" parent="connectionConfig" p:connectionInitializer-ref="bindConnectionInitializer1" p:ldapUrl="%{idp.authn.LDAP.ldapURL1}" /> <bean id="bindConnectionInitializer1" class="org.ldaptive.BindConnectionInitializer" p:bindDn="#{'%{idp.authn.LDAP.bindDN1:undefined}'.trim()}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential" c:password="%{idp.authn.LDAP.bindDNCredential1:undefined}" /> </property> </bean> <!-- DN resolver 2 --> <bean id="bindSearchDnResolver2" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="#{'%{idp.authn.LDAP.baseDN2:undefined}'.trim()}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="#{'%{idp.authn.LDAP.userFilter2:undefined}'.trim()}" p:connectionFactory-ref="bindSearchPooledConnectionFactory2" /> <bean id="bindSearchPooledConnectionFactory2" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindSearchConnectionPool2" /> <bean id="bindSearchConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="bindSearchConnectionFactory2" p:name="search-pool2" /> <bean id="bindSearchConnectionFactory2" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindSearchConnectionConfig2" /> <bean id="bindSearchConnectionConfig2" parent="connectionConfig" p:connectionInitializer-ref="bindConnectionInitializer2" p:ldapUrl="%{idp.authn.LDAP.ldapURL2}" /> <bean id="bindConnectionInitializer2" class="org.ldaptive.BindConnectionInitializer" p:bindDn="#{'%{idp.authn.LDAP.bindDN2:undefined}'.trim()}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential" c:password="%{idp.authn.LDAP.bindDNCredential2:undefined}" /> </property> </bean> <!-- Aggregate authentication --> <bean id="aggregateAuthHandler" class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandler" p:authenticationHandlers-ref="authHandlers" /> <util:map id="authHandlers"> <entry key="directory1" value-ref="authHandler1" /> <entry key="directory2" value-ref="authHandler2" /> </util:map> <!-- Authentication handler 1 --> <bean id="authHandler1" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="bindPooledConnectionFactory1" /> <bean id="bindPooledConnectionFactory1" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindConnectionPool1" /> <bean id="bindConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="bindConnectionFactory1" p:name="bind-pool1" /> <bean id="bindConnectionFactory1" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindConnectionConfig1" /> <bean id="bindConnectionConfig1" parent="connectionConfig" p:ldapUrl="%{idp.authn.LDAP.ldapURL1}" /> <!-- Authentication handler 2 --> <bean id="authHandler2" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="bindPooledConnectionFactory2" /> <bean id="bindPooledConnectionFactory2" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindConnectionPool2" /> <bean id="bindConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="bindConnectionFactory2" p:name="bind-pool2" /> <bean id="bindConnectionFactory2" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindConnectionConfig2" /> <bean id="bindConnectionConfig2" parent="connectionConfig" p:ldapUrl="%{idp.authn.LDAP.ldapURL2}" />

DN resolvers are invoked asynchronously, so all resolvers will be used for each authentication request.

Account State

The LDAP library used (ldaptive) has the ability to extract detailed account status information from the directory during a login. According to ldaptive documentation, no standard for exposing account state data has been universally adopted by LDAP vendors, but the ldaptive library uses a handler which encapsulates account state information. This state contains Warning and Error types that are common to the most popular policy implementations.

Handling account state with OpenLDAP

The OpenLDAP password policy overlay (ppolicy), provides various password policy features. In some cases it can be desirable to be able to inform users whether a login is failed because of invalid credentials, an expired password, a locked account or give password expiration warning. In that cases, OpenLDAP password policy overlay adds account state information in LDAP responses.

In the IdP, the LDAP authn backend can be configured to handle the account state. The file authn/ldap-authn-config.xml has comments with instructions. The detailed configuration is:

 

ldap-authn-config.xml
<!-- 1. Add some beans --> <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.PasswordPolicyAuthenticationResponseHandler" /> <bean id="authenticationControl" class="org.ldaptive.control.PasswordPolicyControl" /> <!-- 2. Comment out the bean of the handler with the same id, used for Active Directory: --> <!-- <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" /> --> <!-- 3. In the existing authHandler bean definition, add the attribute p:authenticationControls-ref="authenticationControl": --> <bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="bindPooledConnectionFactory" p:authenticationControls-ref="authenticationControl" /> <!-- 4. In the authenticator bean definition, add the attribute p:authenticationResponseHandlers-ref="authenticationResponseHandler". Given that there are multiple authenticators, this attribute must be added to the authenticator in use (defined in ldap.properties, in idp.authn.LDAP.authenticator), e.g. if anonSearchAuthenticator is used, the definition could be: --> <bean name="anonSearchAuthenticator" class="org.ldaptive.auth.Authenticator" p:authenticationResponseHandlers-ref="authenticationResponseHandler" >

With that configuration and the default flow definitions, the user can be informed on the login page if the password is expired or is near expiration (messages can be customized in messages/authn-messages.properties).

Locked Accounts:

To inform the user of a locked account, some configuration is needed to detect the error code informed by the LDAP validation action.

In authn/password-authn-config.xml, add an entry to the message clasification rules in  <util:map id="shibboleth.authn.Password.ClassifiedMessageMap">

password-authn-config.xml
<entry key="AccountLocked"> <list> <value>ACCOUNT_LOCKED</value> </list> </entry>

 

This maps the error code to a AccountLocked event. It will run the empty user flow authn/conditions/account-locked and then pass control back to the form. With this configuration, the user gets the message "Your account is locked".

Debug information:

Details of the AuthenticationResponse received, including the password policy controls, can be viewed using the TRACE log level in the logger of name "net.shibboleth.idp" (edit logback.xml).       

Active Directory Configuration

The file authn/ldap-authn-config.xml comes with definitions to configure Active Directory authentication response handlers against a single directory.

Active Directory does not fully support extensible match rules (https://msdn.microsoft.com/en-us/library/cc223241.aspx).

Active Directory (by default) does not support anonymous queries (https://technet.microsoft.com/en-us/library/Cc755809%28v=WS.10%29.aspx).

Using an entry resolver to generate password expiration warnings

<!-- authenticator with entry resolver--> <bean id="adAuthenticator" class="org.ldaptive.auth.Authenticator" p:entryResolver-ref="bindSearchEntryResolver" p:authenticationResponseHandlers-ref="authenticationResponseHandler" p:resolveEntryOnFailure="false"> <constructor-arg index="0" ref="formatDnResolver" /> <constructor-arg index="1" ref="authHandler" /> </bean>   <!-- authentication response handler that defines a password age (in milliseconds), which is the length of time until a password expires --> <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" ><constructor-arg value="%{idp.authn.LDAP.passwordAge}" /></bean>   <!-- Add an entry resolver to read the pwdLastSet, must be included in idp.authn.LDAP.returnAttributes --> <bean id="bindSearchEntryResolver" class="org.ldaptive.auth.PooledSearchEntryResolver" p:connectionFactory-ref="entryResolverPooledConnectionFactory" /> <bean id="entryResolverPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="entryResolverConnectionPool" /> <bean id="entryResolverConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="entryResolverConnectionFactory" p:name="entry-resolver-pool" /> <bean id="entryResolverConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="entryResolverConnectionConfig" /> <bean id="entryResolverConnectionConfig" parent="connectionConfig" p:connectionInitializer-ref="entryResolverConnectionInitializer" /> <bean id="entryResolverConnectionInitializer" class="org.ldaptive.BindConnectionInitializer" p:bindDn="%{idp.authn.LDAP.entryResolver.bindDN}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential"> <constructor-arg value="%{idp.authn.LDAP.entryResolver.bindDNCredential}" /> </bean> </property> </bean>  

 

Example for two Active Directories with two DN Resolvers for each

This example uses directed BaseDN's with LDAP filters, and binds the queries.

<!-- Define Directory1 connection pool --> <bean id="adConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" abstract="true" p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:3000}" p:poolConfig-ref="adPoolConfig1" p:pruneStrategy-ref="adPruneStrategy1" p:validator-ref="adSearchValidator1" p:failFastInitialize="%{idp.pool.LDAP.failFastInitialize:false}" /> <bean id="adPoolConfig1" class="org.ldaptive.pool.PoolConfig" p:minPoolSize="%{idp.pool.LDAP.minSize:3}" p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}" p:validateOnCheckOut="%{idp.pool.LDAP.validateOnCheckout:false}" p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}" p:validatePeriod="%{idp.pool.LDAP.validatePeriod:300}" /> <bean id="adPruneStrategy1" class="org.ldaptive.pool.IdlePruneStrategy" p:prunePeriod="%{idp.pool.LDAP.prunePeriod:300}" p:idleTime="%{idp.pool.LDAP.idleTime:600}" /> <bean id="adSearchValidator1" class="org.ldaptive.pool.SearchValidator" /> <!-- Directory1 connection pool settings --> <bean id="adConnectionConfig1" class="org.ldaptive.ConnectionConfig" abstract="true" p:ldapUrl="%{idp.authn.LDAP.ldapURL1}" p:useStartTLS="%{idp.authn.LDAP.useStartTLS1:true}" p:useSSL="%{idp.authn.LDAP.useSSL1:false}" p:connectTimeout="%{idp.authn.LDAP.connectTimeout1:3000}" p:sslConfig-ref="adSslConfig1" /> <alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="adSslConfig1" /> <!-- Define Directory2 connection pool --> <bean id="adConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" abstract="true" p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:3000}" p:poolConfig-ref="adPoolConfig2" p:pruneStrategy-ref="adPruneStrategy2" p:validator-ref="adSearchValidator2" p:failFastInitialize="%{idp.pool.LDAP.failFastInitialize:false}" /> <bean id="adPoolConfig2" class="org.ldaptive.pool.PoolConfig" p:minPoolSize="%{idp.pool.LDAP.minSize:3}" p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}" p:validateOnCheckOut="%{idp.pool.LDAP.validateOnCheckout:false}" p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}" p:validatePeriod="%{idp.pool.LDAP.validatePeriod:300}" /> <bean id="adPruneStrategy2" class="org.ldaptive.pool.IdlePruneStrategy" p:prunePeriod="%{idp.pool.LDAP.prunePeriod:300}" p:idleTime="%{idp.pool.LDAP.idleTime:600}" /> <bean id="adSearchValidator2" class="org.ldaptive.pool.SearchValidator" /> <!-- Directory2 connection pool settings --> <bean id="adConnectionConfig2" class="org.ldaptive.ConnectionConfig" abstract="true" p:ldapUrl="%{idp.authn.LDAP.ldapURL3}" p:useStartTLS="%{idp.authn.LDAP.useStartTLS3:true}" p:useSSL="%{idp.authn.LDAP.useSSL3:false}" p:connectTimeout="%{idp.authn.LDAP.connectTimeout3:3000}" p:sslConfig-ref="adSslConfig2" /> <alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="adSslConfig2" /> <!-- ldap.properties "idp.authn.LDAP.authenticator = adAggregateAuthenticator" --> <bean id="adAggregateAuthenticator" class="org.ldaptive.auth.Authenticator" p:authenticationResponseHandlers-ref="adAuthenticationResponseHandler"> <constructor-arg index="0" ref="adAggregateDnResolver" /> <constructor-arg index="1" ref="adAggregateAuthHandler" /> </bean> <bean id="adAuthenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" /> <bean id="adAggregateDnResolver" class="org.ldaptive.auth.AggregateDnResolver"> <constructor-arg index="0" ref="adDnResolvers" /> </bean> <bean id="adAggregateAuthHandler" class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandler" p:authenticationHandlers-ref="adAuthHandlers" /> <util:map id="adDnResolvers"> <entry key="directory1_filter1" value-ref="adDnResolver1" /> <entry key="directory1_filter2" value-ref="adDnResolver2" /> <entry key="directory2_filter3" value-ref="adDnResolver3" /> <entry key="directory2_filter4" value-ref="adDnResolver4" /> </util:map> <!-- Define two DN resolvers that use bind search against the Directory1 directory --> <bean id="adDnResolver1" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN1}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch1:false}" p:userFilter="%{idp.authn.LDAP.userFilter1}" p:connectionFactory-ref="adBindSearchPooledConnectionFactory1" /> <bean id="adDnResolver2" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN2}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch2:false}" p:userFilter="%{idp.authn.LDAP.userFilter2}" p:connectionFactory-ref="adBindSearchPooledConnectionFactory1" /> <!-- Define two DN resolvers that use bind search against the Directory2 directory --> <bean id="adDnResolver3" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN3}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch3:false}" p:userFilter="%{idp.authn.LDAP.userFilter3}" p:connectionFactory-ref="adBindSearchPooledConnectionFactory2" /> <bean id="adDnResolver4" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN4}" p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch4:false}" p:userFilter="%{idp.authn.LDAP.userFilter4}" p:connectionFactory-ref="adBindSearchPooledConnectionFactory2" /> <!-- Define Directory1 Search-pool --> <bean id="adBindSearchPooledConnectionFactory1" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="adBindSearchConnectionPool1" /> <bean id="adBindSearchConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" parent="adConnectionPool1" p:connectionFactory-ref="adBindSearchConnectionFactory1" p:name="adSearch-pool1" /> <bean id="adBindSearchConnectionFactory1" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="adBindSearchConnectionConfig1" /> <bean id="adBindSearchConnectionConfig1" parent="adConnectionConfig1" p:connectionInitializer-ref="adBindConnectionInitializer1" /> <bean id="adBindConnectionInitializer1" class="org.ldaptive.BindConnectionInitializer" p:bindDn="%{idp.authn.LDAP.bindDN1}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential"> <constructor-arg value="%{idp.authn.LDAP.bindDNCredential1}" /> </bean> </property> </bean> <!-- Define Directory2 Search-pool --> <bean id="adBindSearchPooledConnectionFactory2" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="adBindSearchConnectionPool2" /> <bean id="adBindSearchConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" parent="adConnectionPool2" p:connectionFactory-ref="adBindSearchConnectionFactory2" p:name="adSearch-pool2" /> <bean id="adBindSearchConnectionFactory2" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="adBindSearchConnectionConfig2" /> <bean id="adBindSearchConnectionConfig2" parent="adConnectionConfig2" p:connectionInitializer-ref="adBindConnectionInitializer2" /> <bean id="adBindConnectionInitializer2" class="org.ldaptive.BindConnectionInitializer" p:bindDn="%{idp.authn.LDAP.bindDN3}"> <property name="bindCredential"> <bean class="org.ldaptive.Credential"> <constructor-arg value="%{idp.authn.LDAP.bindDNCredential3}" /> </bean> </property> </bean> <util:map id="adAuthHandlers"> <entry key="directory1_filter1" value-ref="adAuthHandler1" /> <entry key="directory1_filter2" value-ref="adAuthHandler1" /> <entry key="directory2_filter3" value-ref="adAuthHandler2" /> <entry key="directory2_filter4" value-ref="adAuthHandler2" /> </util:map> <!-- Use the same authentication handler for both Directory1 DN resolvers --> <bean id="adAuthHandler1" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="adBindPooledConnectionFactory1" /> <bean id="adBindPooledConnectionFactory1" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="adBindConnectionPool1" /> <bean id="adBindConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" parent="adConnectionPool1" p:connectionFactory-ref="adBindConnectionFactory1" p:name="adBind-pool1" /> <bean id="adBindConnectionFactory1" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="adBindConnectionConfig1" /> <bean id="adBindConnectionConfig1" parent="adConnectionConfig1" /> <!-- Use the same authentication handler for both Directory2 DN resolvers --> <bean id="adAuthHandler2" class="org.ldaptive.auth.PooledBindAuthenticationHandler" p:connectionFactory-ref="adBindPooledConnectionFactory2" /> <bean id="adBindPooledConnectionFactory2" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="adBindConnectionPool2" /> <bean id="adBindConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" parent="adConnectionPool2" p:connectionFactory-ref="adBindConnectionFactory2" p:name="adBind-pool2" /> <bean id="adBindConnectionFactory2" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="adBindConnectionConfig2" /> <bean id="adBindConnectionConfig2" parent="adConnectionConfig2" />

Add missing Active Directory account state errors

ValidateUsernamePasswordAgainstLDAP authentication response.  If adAuthenticator is the authenticator set in the idp.authn.LDAP.authenticator property, Short Description values are contained in the response.  If bindSearchAuthenticator  is the authenticator set in the idp.authn.LDAP.authenticator property, HEX values are contained in the response. It is possible to use either or both as outlined in the following example. (http://ldapwiki.willeke.com/wiki/Common%20Active%20Directory%20Bind%20Errors)

...  <entry key="AccountDisabled"> <list> <value>ACCOUNT_DISABLED</value> <value>533</value> </list> </entry> <entry key="AccountExpired"> <list> <value>ACCOUNT_EXPIRED</value> </list> </entry> <entry key="AccountLocked"> <list> <value>ACCOUNT_LOCKED_OUT</value> <value>775</value> </list> </entry> <entry key="ChangePassword"> <list> <value>PASSWORD_EXPIRED</value> <value>PASSWORD_MUST_CHANGE</value> <value>532</value> </list> </entry> ...
... AccountDisabled = account-disabled AccountExpired = account-expired AccountLocked = account-locked ChangePassword = change-password account-disabled.message = Your account is disabled. account-expired.message = Your account has expired. account-locked.message = Your account is locked. change-password.message = You must change your password before authenticating here. ...

Notes

TBD