<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body bgcolor="#FFFFFF" text="#000000">
I didnt see alot of documentation for authenticating against
multiple OU's in AD in shibboleth IdP v3.2.1 so I thought i'd share
my setup in case anyone else is trying to do the same thing. In our
AD these are all top level OU's and we have some OU's that we dont
want searched so we cant use subtreeSearch. This is based on the
example from the shibboleth LDAPAuthnConfiguration doc titled
"Complete example with DN resolvers and authentication handlers for
bindSearch" which is for 2 AD servers with 2 directories each. While
this worked for us, we had 1 AD server with 4 directories so we
changed it a bit to fit us better. After making the changes to
ldap-authn-config.xml and ldap.properties we could login OK, but
attributes werent being released. I realized it was because
attribute-resolver.xml by default only had 1 dataconnector to
release attributes for 1 directory so we had to modify that to add
our other 3 dataconnectors as failovers. <br>
<br>
Active Directory doesnt support extensible match rules else we could
of just done <span class="s1">idp.authn.LDAP.userFilter=</span><span
style="color: rgb(34,34,34);">(&(|(ou:dn:=people)(ou:dn:=</span><span
style="color: rgb(34,34,34);">guests))(uid={user})) and saved
ourselves alot of work. :)</span><br>
<br>
I actually dont know java beans (or really shibboleth for that
matter), so if someone sees a more elegant way to do this plz let me
know. <br>
<br>
Added this config for adAuthenticator at the end of
ldap-authn-config.xml, left the existing defined configs untouched:<br>
<br>
<!-- Active Directory Configuration for 1 server with 4 OU's
--><br>
<bean id="adAuthenticator"
class="org.ldaptive.auth.Authenticator"
p:authenticationResponseHandlers-ref="authenticationResponseHandler"<br>
p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}"><br>
<constructor-arg index="0" ref="formatDnResolver" /><br>
<constructor-arg index="1" ref="authHandler" /><br>
</bean><br>
<bean id="authenticationResponseHandler"
class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler"
/><br>
<br>
<!-- Define Directory1 connection pool --><br>
<bean id="adConnectionPool"
class="org.ldaptive.pool.BlockingConnectionPool" abstract="true"<br>
p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:3000}"<br>
p:poolConfig-ref="adPoolConfig"<br>
p:pruneStrategy-ref="adPruneStrategy"<br>
p:validator-ref="adSearchValidator"<br>
p:failFastInitialize="%{idp.pool.LDAP.failFastInitialize:false}"
/><br>
<bean id="adPoolConfig" class="org.ldaptive.pool.PoolConfig"<br>
p:minPoolSize="%{idp.pool.LDAP.minSize:3}"<br>
p:maxPoolSize="%{idp.pool.LDAP.maxSize:10}"<br>
p:validateOnCheckOut="%{idp.pool.LDAP.validateOnCheckout:false}"<br>
p:validatePeriodically="%{idp.pool.LDAP.validatePeriodically:true}"<br>
p:validatePeriod="%{idp.pool.LDAP.validatePeriod:300}" /><br>
<bean id="adPruneStrategy"
class="org.ldaptive.pool.IdlePruneStrategy"<br>
p:prunePeriod="%{idp.pool.LDAP.prunePeriod:300}"<br>
p:idleTime="%{idp.pool.LDAP.idleTime:600}" /><br>
<bean id="adSearchValidator"
class="org.ldaptive.pool.SearchValidator" /><br>
<!-- Directory1 connection pool settings --><br>
<bean id="adConnectionConfig"
class="org.ldaptive.ConnectionConfig" abstract="true"<br>
p:ldapUrl="%{idp.authn.LDAP.ldapURL}"<br>
p:useStartTLS="%{idp.authn.LDAP.useStartTLS:true}"<br>
p:useSSL="%{idp.authn.LDAP.useSSL:false}"<br>
p:connectTimeout="%{idp.authn.LDAP.connectTimeout:3000}"<br>
p:sslConfig-ref="adSslConfig" /><br>
<alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}"
alias="adSslConfig" /><br>
<!-- ldap.properties "idp.authn.LDAP.authenticator =
adAggregateAuthenticator" --><br>
<bean id="adAggregateAuthenticator"
class="org.ldaptive.auth.Authenticator"<br>
p:authenticationResponseHandlers-ref="adAuthenticationResponseHandler"><br>
<constructor-arg index="0" ref="adAggregateDnResolver"
/><br>
<constructor-arg index="1" ref="adAggregateAuthHandler"
/><br>
</bean><br>
<bean id="adAuthenticationResponseHandler"
class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler"
/><br>
<bean id="adAggregateDnResolver"
class="org.ldaptive.auth.AggregateDnResolver"><br>
<constructor-arg index="0" ref="adDnResolvers" /><br>
</bean><br>
<bean id="adAggregateAuthHandler"
class="org.ldaptive.auth.AggregateDnResolver$AuthenticationHandler"<br>
p:authenticationHandlers-ref="adAuthHandlers" /><br>
<util:map id="adDnResolvers"><br>
<entry key="directory_filter1" value-ref="adDnResolver1"
/><br>
<entry key="directory_filter2" value-ref="adDnResolver2"
/><br>
<entry key="directory_filter3" value-ref="adDnResolver3"
/><br>
<entry key="directory_filter4" value-ref="adDnResolver4"
/><br>
</util:map><br>
<!-- Define four DN resolvers that bind search against the
Directory --><br>
<bean id="adDnResolver1"
class="org.ldaptive.auth.PooledSearchDnResolver"<br>
p:baseDn="%{idp.authn.LDAP.baseDN1}"<br>
p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"<br>
p:userFilter="%{idp.authn.LDAP.userFilter}"<br>
p:connectionFactory-ref="adBindSearchPooledConnectionFactory" /><br>
<bean id="adDnResolver2"
class="org.ldaptive.auth.PooledSearchDnResolver"<br>
p:baseDn="%{idp.authn.LDAP.baseDN2}"<br>
p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"<br>
p:userFilter="%{idp.authn.LDAP.userFilter}"<br>
p:connectionFactory-ref="adBindSearchPooledConnectionFactory" /><br>
<bean id="adDnResolver3"
class="org.ldaptive.auth.PooledSearchDnResolver"<br>
p:baseDn="%{idp.authn.LDAP.baseDN3}"<br>
p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"<br>
p:userFilter="%{idp.authn.LDAP.userFilter}"<br>
p:connectionFactory-ref="adBindSearchPooledConnectionFactory" /><br>
<bean id="adDnResolver4"
class="org.ldaptive.auth.PooledSearchDnResolver"<br>
p:baseDn="%{idp.authn.LDAP.baseDN4}"<br>
p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"<br>
p:userFilter="%{idp.authn.LDAP.userFilter}"<br>
p:connectionFactory-ref="adBindSearchPooledConnectionFactory" /><br>
<!-- Define Directory1 Search-pool --><br>
<bean id="adBindSearchPooledConnectionFactory"
class="org.ldaptive.pool.PooledConnectionFactory"<br>
p:connectionPool-ref="adBindSearchConnectionPool" /><br>
<bean id="adBindSearchConnectionPool"
class="org.ldaptive.pool.BlockingConnectionPool"<br>
parent="adConnectionPool"<br>
p:connectionFactory-ref="adBindSearchConnectionFactory"<br>
p:name="adSearch-pool" /><br>
<bean id="adBindSearchConnectionFactory"
class="org.ldaptive.DefaultConnectionFactory"<br>
p:connectionConfig-ref="adBindSearchConnectionConfig" /><br>
<bean id="adBindSearchConnectionConfig"<br>
parent="adConnectionConfig"<br>
p:connectionInitializer-ref="adBindConnectionInitializer"
/><br>
<bean id="adBindConnectionInitializer"
class="org.ldaptive.BindConnectionInitializer"<br>
p:bindDn="%{idp.authn.LDAP.bindDN}"><br>
<property name="bindCredential"><br>
<bean class="org.ldaptive.Credential"><br>
<constructor-arg
value="%{idp.authn.LDAP.bindDNCredential}" /><br>
</bean><br>
</property><br>
</bean><br>
<util:map id="adAuthHandlers"><br>
<entry key="directory_filter1" value-ref="adAuthHandler1"
/><br>
<entry key="directory_filter2" value-ref="adAuthHandler1"
/><br>
<entry key="directory_filter3" value-ref="adAuthHandler1"
/><br>
<entry key="directory_filter4" value-ref="adAuthHandler1"
/><br>
</util:map><br>
<!-- authentication handler for Directory DN resolver --><br>
<bean id="adAuthHandler1"
class="org.ldaptive.auth.PooledBindAuthenticationHandler"<br>
p:connectionFactory-ref="adBindPooledConnectionFactory"
/><br>
<bean id="adBindPooledConnectionFactory"
class="org.ldaptive.pool.PooledConnectionFactory"<br>
p:connectionPool-ref="adBindConnectionPool" /><br>
<bean id="adBindConnectionPool"
class="org.ldaptive.pool.BlockingConnectionPool"<br>
parent="adConnectionPool"<br>
p:connectionFactory-ref="adBindConnectionFactory"<br>
p:name="adBind-pool" /><br>
<bean id="adBindConnectionFactory"
class="org.ldaptive.DefaultConnectionFactory"<br>
p:connectionConfig-ref="adBindConnectionConfig" /><br>
<bean id="adBindConnectionConfig"<br>
parent="adConnectionConfig" /><br>
<br>
ldap.properties:<br>
<br>
# LDAP authentication configuration, see authn/ldap-authn-config.xml<br>
# Note, this doesn't apply to the use of JAAS<br>
<br>
## Authenticator strategy, either anonSearchAuthenticator,
bindSearchAuthenticator, directAuthenticator, adAuthenticator<br>
idp.authn.LDAP.authenticator =
adAggregateAuthenticator<br>
<br>
## Connection properties ##<br>
idp.authn.LDAP.ldapURL =
<a class="moz-txt-link-freetext" href="ldaps://ad1.skool.edu:636">ldaps://ad1.skool.edu:636</a> <a class="moz-txt-link-freetext" href="ldaps://ad2.skool.edu:636">ldaps://ad2.skool.edu:636</a><br>
idp.authn.LDAP.useStartTLS = false<br>
idp.authn.LDAP.useSSL = true<br>
idp.authn.LDAP.connectTimeout = 3000<br>
<br>
## SSL configuration, either jvmTrust, certificateTrust, or
keyStoreTrust<br>
idp.authn.LDAP.sslConfig = certificateTrust<br>
## If using certificateTrust above, set to the trusted certificate's
path<br>
idp.authn.LDAP.trustCertificates =
%{idp.home}/credentials/ldap-server.crt<br>
## If using keyStoreTrust above, set to the truststore path<br>
idp.authn.LDAP.trustStore =
%{idp.home}/credentials/ldap-server.truststore<br>
<br>
## Return attributes during authentication<br>
## NOTE: there is a separate property used for attribute resolution<br>
idp.authn.LDAP.returnAttributes =
passwordExpirationTime,loginGraceRemaining<br>
<br>
## DN resolution properties ##<br>
<br>
# Search DN resolution, used by anonSearchAuthenticator,
bindSearchAuthenticator<br>
# for AD: CN=Users,DC=example,DC=org<br>
#<br>
idp.authn.LDAP.baseDN1 =
OU=folder1,DC=skool,DC=edu<br>
idp.authn.LDAP.baseDN2 =
OU=subfolder1,OU=folder2,DC=skool,DC=edu<br>
idp.authn.LDAP.baseDN3 =
OU=folder3,DC=skool,DC=edu<br>
idp.authn.LDAP.baseDN4 =
OU=folder4,DC=skool,DC=edu<br>
idp.authn.LDAP.subtreeSearch = false<br>
#idp.authn.LDAP.userFilter = (uid={user})<br>
idp.authn.LDAP.userFilter = (mail={user})<br>
# bind search configuration <br>
# for AD: <a class="moz-txt-link-abbreviated" href="mailto:idp.authn.LDAP.bindDN=adminuser@domain.com">idp.authn.LDAP.bindDN=adminuser@domain.com</a><br>
idp.authn.LDAP.bindDN =
CN=ADadmin,ou=managers,dc=skool,dc=edu<br>
idp.authn.LDAP.bindDNCredential =
secretsquirrel66!!!<br>
<br>
# Format DN resolution, used by directAuthenticator, adAuthenticator<br>
# for AD use <a class="moz-txt-link-abbreviated" href="mailto:idp.authn.LDAP.dnFormat=%s@domain.com">idp.authn.LDAP.dnFormat=%s@domain.com</a> <br>
idp.authn.LDAP.dnFormat =
uid=%s,ou=people,dc=example,dc=org<br>
<br>
# LDAP attribute configuration, see attribute-resolver.xml<br>
# Note, this likely won't apply to the use of legacy V2 resolver
configurations<br>
idp.attribute.resolver.LDAP.ldapURL =
%{idp.authn.LDAP.ldapURL}<br>
idp.attribute.resolver.LDAP.baseDN1 =
%{idp.authn.LDAP.baseDN1:undefined}<br>
idp.attribute.resolver.LDAP.baseDN2 =
%{idp.authn.LDAP.baseDN2:undefined}<br>
idp.attribute.resolver.LDAP.baseDN3 =
%{idp.authn.LDAP.baseDN3:undefined}<br>
idp.attribute.resolver.LDAP.baseDN4 =
%{idp.authn.LDAP.baseDN4:undefined}<br>
idp.attribute.resolver.LDAP.bindDN =
%{idp.authn.LDAP.bindDN:undefined}<br>
idp.attribute.resolver.LDAP.bindDNCredential =
%{idp.authn.LDAP.bindDNCredential:undefined}<br>
idp.attribute.resolver.LDAP.useStartTLS =
%{idp.authn.LDAP.useStartTLS:true}<br>
idp.attribute.resolver.LDAP.trustCertificates =
%{idp.authn.LDAP.trustCertificates:undefined}<br>
#idp.attribute.resolver.LDAP.searchFilter =
(uid=$resolutionContext.principal)<br>
idp.attribute.resolver.LDAP.searchFilter =
(mail=$requestContext.principalName)<br>
idp.attribute.resolver.LDAP.returnAttributes =
givenname,mail,miservice,samaccountname,sn<br>
<br>
The dataconnectors from attribute-resolver.xml. Basically if the
search doesnt match in an OU it fails to the next.<br>
<br>
<resolver:DataConnector id="myLDAP" xsi:type="dc:LDAPDirectory"<br>
ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"<br>
baseDN="%{idp.attribute.resolver.LDAP.baseDN1}" <br>
principal="%{idp.attribute.resolver.LDAP.bindDN}"<br>
principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"<br>
noResultIsError="True"<br>
useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}"><br>
<br>
<resolver:FailoverDataConnector ref="myLDAP2" /><br>
<br>
<dc:FilterTemplate><br>
<![CDATA[<br>
%{idp.attribute.resolver.LDAP.searchFilter}<br>
]]><br>
</dc:FilterTemplate><br>
<dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes><br>
<dc:LDAPProperty name="java.naming.referral"
value="follow"/><br>
<dc:StartTLSTrustCredential id="LDAPtoIdPCredential"
xsi:type="sec:X509ResourceBacked"><br>
<sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate><br>
</dc:StartTLSTrustCredential><br>
<br>
</resolver:DataConnector><br>
<br>
<resolver:DataConnector id="myLDAP2"
xsi:type="dc:LDAPDirectory"<br>
ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"<br>
baseDN="%{idp.attribute.resolver.LDAP.baseDN2}" <br>
principal="%{idp.attribute.resolver.LDAP.bindDN}"<br>
principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"<br>
noResultIsError="True"<br>
useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}"><br>
<br>
<resolver:FailoverDataConnector ref="myLDAP3" /><br>
<dc:FilterTemplate><br>
<![CDATA[<br>
%{idp.attribute.resolver.LDAP.searchFilter}<br>
]]><br>
</dc:FilterTemplate><br>
<dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes><br>
<dc:LDAPProperty name="java.naming.referral"
value="follow"/><br>
<dc:StartTLSTrustCredential id="LDAPtoIdPCredential"
xsi:type="sec:X509ResourceBacked"><br>
<sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate><br>
</dc:StartTLSTrustCredential><br>
<br>
</resolver:DataConnector><br>
<br>
And so on for myLDAP3 & 4. On The last entry leave out the
<resolver:FailoverDataConnector><br>
<br>
</body>
</html>