Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: update Multiple Directories example for IDP5

Current File(s): conf/authn/password-authn-config.xml, conf/ldap.properties, conf/authn/authn.properties
Format: Native Spring, Properties

...

The idp.authn.LDAP.authenticator property controls the workflow for how authentication occurs against the LDAP directory for most “simple” cases by automatically configuring a number of underlying objects based on a set of built-in “authenticator types” supported by the ldaptive library.

anonSearchAuthenticator

Performs an anonymous search for the user's DN

bindSearchAuthenticator

Binds with a configured DN as a service account, 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).

...

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)

disabled

Does not allow SSL or startTLS connections.

We have tentative plans to deprecate the “jvmTrust” option, which has already been removed from the attribute resolution side of the software, as it is bad practice and has been a source of serious security flaws.

...

Expand
titleProperties

A number of properties are found in ldap.properties to configure LDAP authentication global defaults. Most of the time, this is sufficient to deal with most configurations without having to delve into modifying any beans, unless you're trying to chain together separately configured back-ends.

Note that the big "override everything" hook tends to be the idp.authn.LDAP.authenticator property, as most of the other properties auto-configure specific aspects of one of the built-in Authenticator beans.

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.connectTimeout

Duration

PT3S

Time to wait for the TCP connection to occur.

idp.authn.LDAP.responseTimeout

Duration

PT3S

Time to wait for an LDAP response message. (Applies to every request except startTLS)

idp.authn.LDAP.startTLSTimeout

Duration

PT3S

Time to wait for a startTLS response message.

idp.authn.LDAP.autoReconnect

Boolean

true

Whether lost connections should be automatically reopened.

idp.authn.LDAP.reconnectTimeout

Duration

PT10S

Time to wait for a connection to reconnect.

idp.authn.LDAP.connectionStrategy

Enumeration

ACTIVE_PASSIVE

Connection strategy to use when multiple URLs are supplied, one of ACTIVE_PASSIVE, ROUND_ROBIN, RANDOM

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. NOTE: Do not set this property if using the adAuthenticator, it is not supported and you will get a WARN message in the log each time a user authenticates. (Authentication still works, though.)

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, usually set via %{idp.home}/credentials/secrets.properties

idp.authn.LDAP.dnFormat

String

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

idp.authn.LDAP.resolveEntryOnFailure

Boolean

false

Whether the user's LDAP entry should be returned in the authentication response even when the user bind fails.

idp.authn.LDAP.resolveEntryWithBindDN

Boolean

false

Whether the user's LDAP entry should be resolved with the bindDN credentials rather than as the authenticated user.

idp.authn.LDAP.usePasswordPolicy

Boolean

false

Whether to use the Password Policy Control.

idp.authn.LDAP.usePasswordExpiration

Boolean

false

Whether to use the Password Expired Control.

idp.authn.LDAP.activeDirectory

Boolean

false

If you are using Active Directory, this switch will attempt to use the account states defined by AD. Note that this flag is unnecessary if you are using the 'adAuthenticator', although it is necessary to use the accountStateExpirationPeriod and accountStateWarningPeriod properties. It is meant to be specified with one of the other authenticator types.

idp.authn.LDAP.freeIPADirectory

Boolean

false

If you are using the FreeIPA LDAP, this switch will attempt to use the account states defined by that product.

idp.authn.LDAP.eDirectory

Boolean

false

If you are using the EDirectory LDAP, this switch will attempt to use the account states defined by that product.

idp.authn.LDAP.disablePooling

Boolean

false

Whether connection pools should be used for LDAP connections used for authentication.

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

Duration

PT5M

Duration between validation, if idp.pool.LDAP.validatePeriodically is true

idp.pool.LDAP.validateDN

String

DN to search with the validateFilter, default is the rootDSE

idp.pool.LDAP.validateFilter

String

(objectClass=*)

Search filter to execute in order to validate a pooled connection

idp.pool.LDAP.prunePeriod

Duration

PT5M

Duration between looking for idle connections to reduce the pool back to its minimum size

idp.pool.LDAP.idleTime

Duration

PT10M

Duration connections must be idle to be eligible for pruning

idp.pool.LDAP.blockWaitTime

Duration

PT3S

Duration to wait for a free connection in the pool

idp.authn.LDAP.bindPoolPassivator

Enumeration

none

Controls how connections in the bind pool are passivated. Connections in the bind pool may be in an authenticated state that will not allow validation searches to succeed. This property controls how bind connections are placed back into the pool. If your directory requires searches to be performed by the idp.authn.LDAP.bindDN or anonymously, this property controls that behavior. one of: none, bind, anonymousBind.

...

(As noted in the Properties reference above, this feature is not supported by the adAuthenticator. If you set it, it will result in a WARN message in the logs for each authentication attempt.)

Expand
titleAttribute Retrieval

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

Property

Sample

Result

Property

Sample

Result

idp.authn.LDAP.returnAttributes

uid,

eduPersonAffiliation

Returns the uid and

eduPersonAffiliation attributes.

*

Returns all user attributes on the entry.

*,+

Returns all user and operational attributes on the entry.

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 that data. The easiest way to that is to use the idp.authn.LDAP.resolveEntryWithBindDN=true property. This will configure a separate connection pool using the bind credentials. However, if the attributes you need require different credentials, then following configuration demonstrates how to add a new connection pool for that purpose.

Spring Configuration
Code Block
languagexml
<!-- 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.PooledSearchEntryResolverSearchEntryResolver" p:connectionFactory-ref="entryResolverPooledConnectionFactory" />
<bean id="entryResolverPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPoolconnectionConfig-ref="entryResolverConnectionPool" />
<bean id="entryResolverConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" p:connectionFactory-ref="entryResolverConnectionFactory" pentryResolverConnectionConfig" p:name="entry-resolver-pool" />
<bean id="entryResolverConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="entryResolverConnectionConfig" />
<bean id="entryResolverConnectionConfig" parent="connectionConfig" p:connectionInitializerconnectionInitializers-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 and credentials/secrets.properties respectively. Then set idp.authn.LDAP.authenticator to anonSearchAuthenticator. 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.

Expand
titleDN Resolution

Single Directory with Multiple Branches

<util:list id="shibboleth.authn.Password.Validators

-authn-config.xml:

Expand
titleDN Resolution

Single Directory with Multiple Branches

Extensible Matching

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

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.

Spring Configuration
Code Block
languagexml
<!-- Connection Configuration -->
<bean id="connectionConfig" class="org.ldaptive.ConnectionConfig" abstract="true" p:ldapUrl="%{idp.authn.LDAP.ldapURL}"
      p:useStartTLSldapUrl="%{idp.authn.LDAP.useStartTLS:trueldapURL}"
      p:useSSLuseStartTLS="%{idp.authn.LDAP.useSSLuseStartTLS:falsetrue}"
      p:connectTimeoutDurationconnectTimeout="%{idp.authn.LDAP.connectTimeout:PT3S}"
      p:responseTimeoutDurationresponseTimeout="%{idp.authn.LDAP.responseTimeout:PT3S}"
      p:sslConfig-ref="sslConfig" />

<alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="sslConfig" />

<bean id="jvmTrust" class="org.ldaptive.ssl.SslConfig" />
<bean id="certificateTrust" class="org.ldaptive.ssl.SslConfig">
    <property name="credentialConfig">
        <bean parent="shibboleth.X509ResourceCredentialConfig" p:trustCertificates="%{idp.authn.LDAP.trustCertificates:undefined}" />
    </property>
</bean>
<bean id="keyStoreTrust" class="org.ldaptive.ssl.SslConfig">
 
  <property name="credentialConfig">
  
     <bean parent="shibboleth.KeystoreResourceCredentialConfig" p:truststore="%{idp.authn.LDAP.trustStore:undefined}" />
    </property>
</bean>

<!-- Pool Configuration -->
<bean id="connectionPool" class="org.ldaptive.pool.BlockingConnectionPoolPooledConnectionFactory" abstract="true"
      p:blockWaitTimeDurationblockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
      p:poolConfig-refminPoolSize="poolConfig%{idp.pool.LDAP.minSize:3}"
      p:pruneStrategy-ref="pruneStrategy"
      p:validator-ref="searchValidator"
      p:failFastInitialize="%maxPoolSize="%{idp.pool.LDAP.failFastInitializemaxSize:false}" />
<bean id="poolConfig" class="org.ldaptive.pool.PoolConfig10}"
      p:minPoolSizevalidateOnCheckOut="%{idp.pool.LDAP.minSizevalidateOnCheckout:3false}"
      p:maxPoolSizevalidatePeriodically="%{idp.pool.LDAP.maxSizevalidatePeriodically:10true}"
      p:validateOnCheckOutpruneStrategy-ref="%{idp.pool.LDAP.validateOnCheckout:false}pruneStrategy"
      p:validatePeriodicallyvalidator-ref="%{idp.pool.LDAP.validatePeriodically:true}searchValidator"
      p:validatePeriodDurationfailFastInitialize="%{idp.pool.LDAP.validatePeriodfailFastInitialize:PT5Mfalse}" />
<bean id="pruneStrategy" class="org.ldaptive.pool.IdlePruneStrategy"
      p:prunePeriodDurationprunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
      p:idleTimeDurationidleTime="%{idp.pool.LDAP.idleTime:PT10M}" />
<bean id="searchValidator" class="org.ldaptive.pool.SearchValidator" SearchConnectionValidator" p:validatePeriod="%{idp.pool.LDAP.validatePeriod:PT5M}"/>

<!-- Authentication handler -->
<bean id="authHandler" class="org.ldaptive.auth.PooledBindAuthenticationHandlerSimpleBindAuthenticationHandler" p:connectionFactory-ref="bindPooledConnectionFactory" />
<bean id="bindPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" p:connectionPool-ref="bindConnectionPool" />
<bean id="bindConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"

     p:connectionFactory-ref="bindConnectionFactory" p:name="bind-pool"
  /> <bean id="bindConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="bindConnectionConfig" />
<bean id="bindConnectionConfig" parent="connectionConfig" />

<!-- Anonymous Search Configuration -->
<bean name="anonSearchAuthenticator" class="org.ldaptive.auth.Authenticator" p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
    <constructor-arg index="0" ref="anonSearchDnResolver" />
 
  <constructor-arg index="1" ref="authHandler" />
</bean>
<bean id="anonSearchDnResolver" class="net.shibboleth.idp.authn.PooledTemplateSearchDnResolverTemplateSearchDnResolver"
      p:baseDn="#{'%{idp.authn.LDAP.baseDN:undefined}'.trim()}"
      p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
      p:connectionFactory-ref="anonSearchPooledConnectionFactory" >
 
  <constructor-arg index="0" ref="shibboleth.VelocityEngine" />
 
  <constructor-arg index="1" value="#{'%{idp.authn.LDAP.userFilter:undefined}'.trim()}" />
</bean>
<bean id="anonSearchPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory" parent="connectionPool"
      p:connectionPool-refname="anonSearchConnectionPoolsearch-pool"
/> <bean id="anonSearchConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"
      p:connectionFactory-ref="anonSearchConnectionFactory" p:name="search-pool" />
<bean id="anonSearchConnectionFactory" class="org.ldaptive.DefaultConnectionFactory" p:connectionConfig-ref="anonSearchConnectionConfig" />
<bean id="anonSearchConnectionConfig" parent="connectionConfig" />

<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>
  <!/constructor-- Define two DN resolvers that use anonymous search against the same directory -->
arg>
</bean>
<bean id="dnResolver1aggregateAuthHandler" class="org.ldaptive.auth.PooledSearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN1}"AggregateAuthenticationHandler">
      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}"<constructor-arg index="0">
    <!-- Use the same authentication handler for both DN resolvers -->
    <util:map id="authHandlers">
      <entry p:subtreeSearchkey="%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="%{idp.authn.LDAP.userFilter2}"filter1" value-ref="authHandler" />
      <entry  p:connectionFactorykey="filter2" value-ref="anonSearchPooledConnectionFactoryauthHandler" />
<    </util:map>
  </constructor-arg>
</bean>

<!-- Use the same authentication handler for both DN resolvers Define two DN resolvers that use anonymous search against the same directory -->
<util:map<bean id="authHandlersdnResolver1">
    <entry key="filter1" value-ref="authHandler" /> class="org.ldaptive.auth.SearchDnResolver" p:baseDn="%{idp.authn.LDAP.baseDN1}"
     <entry keyp:subtreeSearch="filter2" value-ref="authHandler%{idp.authn.LDAP.subtreeSearch:false}" p:userFilter="%{idp.authn.LDAP.userFilter1}"
      p:connectionFactory-ref="anonSearchPooledConnectionFactory" />
</util:map>
Add the 
<bean id="dnResolver2" class="org.ldaptive.auth.SearchDnResolver" p:baseDn="%{idp.authn.LDAP.
baseDN[12] and 
baseDN2}"
      p:subtreeSearch="%{idp.authn.LDAP.
userFilter[12] properties to conf/ldap.properties. The key values used in
subtreeSearch:false}" p:userFilter="%{idp.authn.LDAP.userFilter2}"
      p:connectionFactory-ref="anonSearchPooledConnectionFactory" />

Add the idp.authn.LDAP.baseDN[12] and idp.authn.LDAP.userFilter[12] properties to conf/ldap.properties. 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.

In addition to these beans, the aggregateAuthenticator bean (in the example above) must be injected into the LDAP credential validator in password-authn-config.xml:

Code Block
Code Block
<util:list id="shibboleth.authn.Password.Validators">
    <!-- Default bean uses the settings defined in ldap.properties -->
    <bean parent="shibboleth.LDAPValidator" p:authenticator-ref="aggregateAuthenticator" />
</util:list>

Multiple Directories

Aggregate DN Resolver

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

Spring Configuration
Code Block
languagexml
<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">
    <util:map id="dnResolvers">
      <entry key="directory1" value-ref="dnResolver1" />
      <entry key="directory2" value-ref="dnResolver2" />
    </util:map>
  </constructor-arg>
</bean>
<bean id="aggregateAuthHandler" class="org.ldaptive.auth.AggregateAuthenticationHandler">
  <constructor-arg index="0">
    <util:map id="authHandlers">
    <!-- Default bean uses the settings defined in ldap.properties -->
    <bean parent="shibboleth.LDAPValidator" p:authenticator-ref="aggregateAuthenticator" />
</util:list>

Multiple Directories

Aggregate DN Resolver

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

Spring Configuration
Code Block
languagexml
<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  <entry key="directory1" value-ref="authHandler1" />
      <entry key="directory2" value-ref="authHandler2" />
    </util:map>
  </constructor-arg>
</bean>
<!-- define DN resolvers and authentication handlers for each directory... -->

Complete example with DN resolvers and authentication handlers for bindSearch

Code Block
languagexml
<!-- 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.AggregateDnResolver$AuthenticationHandlerAuthenticator" p:authenticationHandlers
      c:resolver-ref="authHandlersaggregateDnResolver" />
<util:map id="dnResolvers">
    <entry key="directory1" value-ref="dnResolver1" />
    <entry key="directory2" value-ref="dnResolver2" />
</util:map>
      c:handler-ref="aggregateAuthHandler" />

<!-- Aggregate DN resolution -->
<bean id="aggregateDnResolver" class="org.ldaptive.auth.AggregateDnResolver" p:allowMultipleDns="true">
  <constructor-arg index="0">
    <util:map id="authHandlersdnResolvers">
      <entry key="directory1" value-ref="authHandler1bindSearchDnResolver1" />
      <entry key="directory2" value-ref="authHandler2bindSearchDnResolver2" />>
    </util:map>
  </constructor-arg>
</bean>

<!-- definereusable DNPooledConnectionFactory resolversparent andbean authenticationwith handlerspool for each directory... settings -->

Complete example with DN resolvers and authentication handlers for bindSearch

Code Block
languagexml
<!-- 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
<bean id="pooledConnectionFactory" class="org.ldaptive.PooledConnectionFactory"
    p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
    p:pruneStrategy-ref="pruneStrategy"
    p:validator-ref="searchValidator"
    p:failFastInitialize="%{idp.pool.LDAP.failFastInitialize:false}"
    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}" />

<!-- AggregateDN DNresolver resolution1 -->
<bean id="aggregateDnResolverbindSearchDnResolver1" class="org.ldaptive.auth.AggregateDnResolvernet.shibboleth.idp.authn.TemplateSearchDnResolver"
    p:baseDn="#{'%{idp.authn.LDAP1.baseDN:undefined}'.trim()}"
    p:subtreeSearch="%{idp.authn.LDAP1.subtreeSearch:false}"
      cp:resolversconnectionFactory-ref="dnResolversbindSearchPooledConnectionFactory1" >
     p:allowMultipleDns<constructor-arg index="true0" />
<util:map idref="dnResolversshibboleth.VelocityEngine" />
    <entry<constructor-arg keyindex="directory11" value-ref="bindSearchDnResolver1#{'%{idp.authn.LDAP1.userFilter:undefined}'.trim()}" />
</bean>
<bean   <entry keyid="bindSearchPooledConnectionFactory1" parent="directory2pooledConnectionFactory" value
    p:connectionConfig-ref="bindSearchDnResolver2bindSearchConnectionConfig1" />
</util:map>

<!-- DN resolver 1 --<bean id="bindSearchConnectionConfig1" parent="connectionConfig1" p:connectionInitializers-ref="bindConnectionInitializer1" />
<bean id="bindSearchDnResolver1bindConnectionInitializer1" class="org.ldaptive.auth.PooledSearchDnResolverBindConnectionInitializer"
        p:baseDnbindDn="#{'%{idp.authn.LDAPLDAP1.baseDN1bindDN:undefined}'.trim()}">
    <property  p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"name="bindCredential">
        <bean p:userFilterclass="#{'%{idp.authn.LDAP.userFilter1:undefined}'.trim()}"org.ldaptive.Credential">
            p:connectionFactory-ref="bindSearchPooledConnectionFactory<constructor-arg value="%{idp.authn.LDAP1.bindDNCredential:undefined}" />
   <bean  id="bindSearchPooledConnectionFactory1" class="org.ldaptive.pool.PooledConnectionFactory"  </bean>
    p:connectionPool-ref="bindSearchConnectionPool1" /></property>
</bean>

<bean id="bindSearchConnectionPool1connectionConfig1" class="org.ldaptive.pool.BlockingConnectionPoolConnectionConfig" parentabstract="connectionPooltrue" p:ldapUrl="%{idp.authn.LDAP1.ldapURL}"
     p:connectionFactory-refuseStartTLS="bindSearchConnectionFactory1"
%{idp.authn.LDAP1.useStartTLS:true}"
     p:nameconnectTimeout="search-pool1%{idp.authn.LDAP.connectTimeout:PT3S}"
/> <bean id="bindSearchConnectionFactory1" class="org.ldaptive.DefaultConnectionFactory  p:responseTimeout="%{idp.authn.LDAP.responseTimeout:PT3S}"
      p:connectionConfigsslConfig-ref="bindSearchConnectionConfig1sslConfig" />

<!-- DN resolver 2 -->
<bean id="bindSearchConnectionConfig1bindSearchDnResolver2" parentclass="connectionConfig"
 net.shibboleth.idp.authn.TemplateSearchDnResolver"
    p:connectionInitializer-ref="bindConnectionInitializer1baseDn="#{'%{idp.authn.LDAP2.baseDN:undefined}'.trim()}"
      p:ldapUrlsubtreeSearch="%{idp.authn.LDAPLDAP2.ldapURL1}subtreeSearch:false}"
    p:connectionFactory-ref="bindSearchPooledConnectionFactory2" />
<bean id
    <constructor-arg index="bindConnectionInitializer10" classref="orgshibboleth.ldaptive.BindConnectionInitializerVelocityEngine" />
     p:bindDn<constructor-arg index="1" value="#{'%{idp.authn.LDAPLDAP2.bindDN1userFilter:undefined}'.trim()}" />
</bean>
<bean   <property nameid="bindSearchPooledConnectionFactory2" parent="bindCredentialpooledConnectionFactory">
    <bean class="org.ldaptive.Credential" c:password="%{idp.authn.LDAP.bindDNCredential1:undefined}p:connectionConfig-ref="bindSearchConnectionConfig2" />
<bean id="bindSearchConnectionConfig2"   </property>
</bean>
<!-- DN resolver 2 --parent="connectionConfig2" p:connectionInitializers-ref="bindConnectionInitializer2" />
<bean id="bindSearchDnResolver2bindConnectionInitializer2" class="org.ldaptive.auth.PooledSearchDnResolverBindConnectionInitializer"
        p:baseDnbindDn="#{'%{idp.authn.LDAPLDAP2.baseDN2bindDN:undefined}'.trim()}">
    <property  p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
      p:userFilter="#{'%{idp.authn.LDAP.userFilter2:undefined}'.trim()}"name="bindCredential">
      p:connectionFactory-ref="bindSearchPooledConnectionFactory" /> <bean id="bindSearchPooledConnectionFactory2" class="org.ldaptive.pool.PooledConnectionFactory"Credential">
         p:connectionPool-ref="bindSearchConnectionPool2" /> <bean id="bindSearchConnectionPool2" class="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool" <constructor-arg value="%{idp.authn.LDAP2.bindDNCredential:undefined}" />
      p:connectionFactory-ref="bindSearchConnectionFactory2"  </bean>
    p:name="search-pool2" /></property>
</bean>

<bean id="bindSearchConnectionFactory2connectionConfig2" class="org.ldaptive.DefaultConnectionFactoryConnectionConfig"       p:connectionConfig-ref="bindSearchConnectionConfig2" />
<bean id="bindSearchConnectionConfig2" parent="connectionConfig"
 abstract="true" p:ldapUrl="%{idp.authn.LDAP2.ldapURL}"
    p:useStartTLS="%{idp.authn.LDAP2.useStartTLS:true}"
    p:connectionInitializer-refconnectTimeout="bindConnectionInitializer2%{idp.authn.LDAP.connectTimeout:PT3S}"
      p:ldapUrlresponseTimeout="%{idp.authn.LDAP.ldapURL2responseTimeout:PT3S}"
    p:sslConfig-ref="sslConfig" />

<!-- Aggregate authentication -->
<bean id="bindConnectionInitializer2aggregateAuthHandler" class="org.ldaptive.auth.BindConnectionInitializerAggregateAuthenticationHandler">
  <constructor-arg index="0">
  p:bindDn="#{'%{idp.authn.LDAP.bindDN2:undefined}'.trim()}">  <util:map id="authHandlers">
      <property name="bindCredential" <entry key="directory1" value-ref="authHandler1" />
      <entry  <bean classkey="org.ldaptive.Credentialdirectory2" c:password="%{idp.authn.LDAP.bindDNCredential2:undefined}value-ref="authHandler2" />
    </util:map>
  </property>constructor-arg>
</bean>

<!-- Authentication Aggregatehandler authentication1 -->

<bean id="aggregateAuthHandlerauthHandler1" class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandlerSimpleBindAuthenticationHandler"
      p:authenticationHandlersconnectionFactory-ref="authHandlersbindPooledConnectionFactory1" />
<util:map<bean id="authHandlersbindPooledConnectionFactory1">
    <entry key parent="directory1pooledConnectionFactory" valuep:connectionConfig-ref="authHandler1bindConnectionConfig1" />
    <entry key<bean id="directory2bindConnectionConfig1" value-refparent="authHandler2connectionConfig1" />
</util:map>/>

<!-- Authentication handler 12 -->
<bean id="authHandler1authHandler2" class="org.ldaptive.auth.PooledBindAuthenticationHandlerSimpleBindAuthenticationHandler"
      p:connectionFactory-ref="bindPooledConnectionFactory1bindPooledConnectionFactory2" />
<bean id="bindPooledConnectionFactory1bindPooledConnectionFactory2" classparent="org.ldaptive.pool.PooledConnectionFactory"
     pooledConnectionFactory" p:connectionPoolconnectionConfig-ref="bindConnectionPool1bindConnectionConfig2" />
<bean id="bindConnectionPool1bindConnectionConfig2" classparent="org.ldaptive.pool.BlockingConnectionPool" parent="connectionPool"
      p:connectionFactory-ref="bindConnectionFactory1"
      p:name="bind-pool1connectionConfig2" />

<!-- shared definitions -->

<alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="sslConfig" />

<bean id="jvmTrust" class="org.ldaptive.ssl.SslConfig" />
<bean id="bindConnectionFactory1certificateTrust" class="org.ldaptive.ssl.DefaultConnectionFactorySslConfig">
      p:connectionConfig-ref<property name="bindConnectionConfig1credentialConfig">
/> <bean id="bindConnectionConfig1" parent="connectionConfig"     <bean parent="shibboleth.X509ResourceCredentialConfig" p:ldapUrltrustCertificates="%{idp.authn.LDAP.ldapURL1trustCertificates:undefined}" />
<!--  Authentication handler 2 --></property>
</bean>
<bean id="authHandler2keyStoreTrust" class="org.ldaptive.authssl.PooledBindAuthenticationHandlerSslConfig">
      p:connectionFactory-ref<property name="bindPooledConnectionFactory2credentialConfig" />>
        <bean idparent="bindPooledConnectionFactory2shibboleth.KeystoreResourceCredentialConfig" classp:truststore="org%{idp.ldaptiveauthn.pool.PooledConnectionFactoryLDAP.trustStore:undefined}" />
     p:connectionPool-ref="bindConnectionPool2" /></property>
</bean>

<bean id="bindConnectionPool2pruneStrategy" class="org.ldaptive.pool.BlockingConnectionPoolIdlePruneStrategy"
parent="connectionPool"       p:connectionFactory-refprunePeriod="bindConnectionFactory2"
 %{idp.pool.LDAP.prunePeriod:PT5M}"
    p:nameidleTime="bind-pool2%{idp.pool.LDAP.idleTime:PT10M}" />

<bean id="bindConnectionFactory2searchValidator" class="org.ldaptive.DefaultConnectionFactorySearchConnectionValidator"
 
    p:connectionConfig-refvalidatePeriod="bindConnectionConfig2" />
<bean id="bindConnectionConfig2" parent="connectionConfig"
      p:ldapUrl="%{idp.authnpool.LDAP.ldapURL2validatePeriod:PT5M}" />

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

Expand
titleAccount State

The ldaptive LDAP library has the ability to extract detailed account status information from the directory during authentication. According to the Ldaptive documentation, no standard for exposing account state data has been universally adopted by LDAP vendors, but the 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.

Password Policy Control

The Password Policy for LDAP Directories (draft) standard is implemented by several LDAP directories, including OpenLDAP and Oracle DSEE.  The Password Policy Control is used during an LDAP bind operation to request information about the user's account state.

To enable the Password Policy Control handlers in ldaptive, add the following to conf/ldap.properties:

conf/ldap.properties
Code Block
languagexml
# Use password policy control
idp.authn.LDAP.usePasswordPolicy = true

The user will be informed on the login page if there are any Password Policy warnings or errors (messages can be customized in messages/messages.properties).

Password expiration warnings have been confirmed to work with Oracle DSEE. Please notify us or edit this page if you test successfully with other directory products.

Locked Accounts

To inform the user of a locked account, some configuration is needed to detect the error code returned by the LDAP bind request.

In authn/password-authn-config.xml, add an entry to the message clasification rules defined by shibboleth.authn.Password.ClassifiedMessageMap

password-authn-config.xml
Code Block
languagexml
<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 system 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

Spring Configuration
Code Block
languagexml
<!-- authenticator with entry resolver-->
<bean id="adAuthenticator" class="org.ldaptive.auth.Authenticator" p:entryResolver-ref="bindSearchEntryResolver" p:authenticationResponseHandlersresponseHandlers-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 expiration period and warning period -->
<!-- expiration period is the amount of time since a password was set that it will expire in period notation -->
<!-- expiration period is only used if the msDS-UserPasswordExpiryTimeComputed attributes cannot be read and pwdLastSet can be read -->
<!-- warning period is the amount of time before expiration to produce a warning in period notation. Warning period is only applied if an expiration period can be resolved. -->
<!-- note that this response handler has a default constructor without these properties if you don't want to override the defaults -->
<bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" >
 
  <constructor-arg index="0">
        <bean factory-method="parse" class="java.time.Period">
            <constructor-arg value="%{idp.authn.LDAP.expirationPeriod}" />
   
    </bean>
    </constructor-arg>
    <constructor-arg index="1">
        <bean factory-method="parse" class="java.time.Period">
     
      <constructor-arg value="%{idp.authn.LDAP.warningPeriod}" />
   
    </bean>
 
  </constructor-arg>
</bean>
 
<!-- Add an entry resolver to read the pwdLastSet, must be included in idp.authn.LDAP.returnAttributes -->
<bean id="bindSearchEntryResolver" class="org.ldaptive.auth.PooledSearchEntryResolverSearchEntryResolver" 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-resolver-pool" p:connectionConfig-ref="entryResolverConnectionConfig" />
<bean id="entryResolverConnectionConfig" parent="connectionConfig" p:connectionInitializerconnectionInitializers-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.

Spring Configuration
Code Block
languagexml
<!-- Define Directory1 connection pool -->
    <bean id="adConnectionPool1" class="org.ldaptive.pool.BlockingConnectionPool" abstract="true"
        p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:PT3S}"
        p:poolConfig-ref="adPoolConfig1"
        p:pruneStrategy-ref="adPruneStrategy1"
        p:validator-ref="adSearchValidator1"
 PooledConnectionFactory" abstract="true"
      p:failFastInitializeblockWaitTime="%{idp.pool.LDAP.failFastInitializeblockWaitTime:falsePT3S}"
/>     <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:pruneStrategy-ref="adPruneStrategy1"
      p:validator-ref="adSearchValidator1"
      p:validatePeriodfailFastInitialize="%{idp.pool.LDAP.validatePeriodfailFastInitialize:PT5Mfalse}" />
    <bean id="adPruneStrategy1" class="org.ldaptive.pool.IdlePruneStrategy"

       p:prunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
        p:idleTime="%{idp.pool.LDAP.idleTime:PT10M}" />
   
<bean id="adSearchValidator1" class="org.ldaptiveldaptive.SearchConnectionValidator"
      p:validatePeriod="%{idp.pool.SearchValidator.LDAP.validatePeriod:PT5M}" />
<!-- 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:connectTimeout="%{idp.authn.LDAP.connectTimeout1:PT3S}"
        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:PT3S}"
        p:poolConfig-ref="adPoolConfig2"
        p:pruneStrategy-ref="adPruneStrategy2"
        p:validator-ref="adSearchValidator2"
 PooledConnectionFactory" abstract="true"
      p:failFastInitializeblockWaitTime="%{idp.pool.LDAP.failFastInitializeblockWaitTime:falsePT3S}"
/>     <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:pruneStrategy-ref="adPruneStrategy2"
      p:validator-ref="adSearchValidator2"
      p:validatePeriodfailFastInitialize="%{idp.pool.LDAP.validatePeriodfailFastInitialize:PT5Mfalse}" />
    <bean id="adPruneStrategy2" class="org.ldaptive.pool.IdlePruneStrategy"
 
      p:prunePeriod="%{idp.pool.LDAP.prunePeriod:PT5M}"
        p:idleTime="%{idp.pool.LDAP.idleTime:PT10M}" />
   
<bean id="adSearchValidator2" class="org.ldaptive.pool.SearchValidator="org.ldaptive.SearchConnectionValidator"
      p:validatePeriod="%{idp.pool.LDAP.validatePeriod:PT5M}" />
<!-- 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:connectTimeout="%{idp.authn.LDAP.connectTimeout3:PT3S}"
 
      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:authenticationResponseHandlersresponseHandlers-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$AuthenticationHandlerAggregateAuthenticationHandler"
        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.PooledSearchDnResolverSearchDnResolver"
 
      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.PooledSearchDnResolverSearchDnResolver"
        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.PooledSearchDnResolverSearchDnResolver"
        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.PooledSearchDnResolverSearchDnResolver"
        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:connectionPoolconnectionFactory-ref="adBindSearchConnectionPool1adBindSearchPooledConnectionFactory2" />
<!-- Define Directory1 Search-pool -->
<bean id="adBindSearchConnectionPool1adBindSearchPooledConnectionFactory1" class="org.ldaptive.pool.BlockingConnectionPoolPooledConnectionFactory"
        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:connectionInitializerconnectionInitializers-ref="adBindConnectionInitializer1" />
    <bean id="adBindConnectionInitializer1" class="org.ldaptive.BindConnectionInitializer"
        p:bindDn="%{idp.authn.LDAP.bindDN1}">
    
   <property name="bindCredential">
     
      <bean class="org.ldaptive.Credential">
         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 idp:name="adBindSearchConnectionFactory2adSearch-pool2"
class="org.ldaptive.DefaultConnectionFactory"
        p:connectionConfig-ref="adBindSearchConnectionConfig2" />
 
  <bean id="adBindSearchConnectionConfig2"
         parent="adConnectionConfig2"
 
      p:connectionInitializerconnectionInitializers-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.PooledBindAuthenticationHandlerSimpleBindAuthenticationHandler"

       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.PooledBindAuthenticationHandlerSimpleBindAuthenticationHandler"

       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

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)

password-authn-config.xml
Code Block
languagexml
   ...
        <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>
   ...
messages/messages.properties
Code Block
...
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.
...

...