Page tree
Skip to end of metadata
Go to start of metadata

This describes how to authenticate against Active Directory with multiple OU's with Shibboleth version 3.2.1, specifically 1 AD server (or 2 mirrored servers) with 4 OU's. The LDAP documentation suggests to connect to multiple OU's you can use idp.authn.LDAP.userFilter=(&(|(ou:dn:=people)(ou:dn:=guests))(uid={user})) but unfortunately thats not supported by Active Directory.

Step-by-step guide

 

  1. Add another authenticator to ldap-authn-config.xml

    ldap-authn-config.xml
       <!-- Active Directory Configuration for 1 server with 4 OU's -->
        <bean id="adAuthenticator" class="org.ldaptive.auth.Authenticator" p:authenticationResponseHandlers-ref="authenticationResponseHandler"
            p:resolveEntryOnFailure="%{idp.authn.LDAP.resolveEntryOnFailure:false}">
            <constructor-arg index="0" ref="formatDnResolver" />
            <constructor-arg index="1" ref="authHandler" />
        </bean>
        <bean id="authenticationResponseHandler" class="org.ldaptive.auth.ext.ActiveDirectoryAuthenticationResponseHandler" />
    
    <!-- Define Directory1 connection pool -->
        <bean id="adConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool" abstract="true"
            p:blockWaitTime="%{idp.pool.LDAP.blockWaitTime:3000}"
            p:poolConfig-ref="adPoolConfig"
            p:pruneStrategy-ref="adPruneStrategy"
            p:validator-ref="adSearchValidator"
            p:failFastInitialize="%{idp.pool.LDAP.failFastInitialize:false}" />
        <bean id="adPoolConfig" 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="adPruneStrategy" class="org.ldaptive.pool.IdlePruneStrategy"
            p:prunePeriod="%{idp.pool.LDAP.prunePeriod:300}"
            p:idleTime="%{idp.pool.LDAP.idleTime:600}" />
        <bean id="adSearchValidator" class="org.ldaptive.pool.SearchValidator" />
    <!-- Directory1 connection pool settings -->
        <bean id="adConnectionConfig" class="org.ldaptive.ConnectionConfig" abstract="true"
            p:ldapUrl="%{idp.authn.LDAP.ldapURL}"
            p:useStartTLS="%{idp.authn.LDAP.useStartTLS:true}"
            p:useSSL="%{idp.authn.LDAP.useSSL:false}"
            p:connectTimeout="%{idp.authn.LDAP.connectTimeout:3000}"
            p:sslConfig-ref="adSslConfig" />
        <alias name="%{idp.authn.LDAP.sslConfig:certificateTrust}" alias="adSslConfig" />
    <!-- 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="directory_filter1" value-ref="adDnResolver1" />
            <entry key="directory_filter2" value-ref="adDnResolver2" />
            <entry key="directory_filter3" value-ref="adDnResolver3" />
            <entry key="directory_filter4" value-ref="adDnResolver4" />
        </util:map>
    <!-- Define four DN resolvers that bind search against the Directory -->
        <bean id="adDnResolver1" class="org.ldaptive.auth.PooledSearchDnResolver"
            p:baseDn="%{idp.authn.LDAP.baseDN1}"
            p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
            p:userFilter="%{idp.authn.LDAP.userFilter}"
            p:connectionFactory-ref="adBindSearchPooledConnectionFactory" />
        <bean id="adDnResolver2" class="org.ldaptive.auth.PooledSearchDnResolver"
            p:baseDn="%{idp.authn.LDAP.baseDN2}"
            p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
            p:userFilter="%{idp.authn.LDAP.userFilter}"
            p:connectionFactory-ref="adBindSearchPooledConnectionFactory" />
        <bean id="adDnResolver3" class="org.ldaptive.auth.PooledSearchDnResolver"
            p:baseDn="%{idp.authn.LDAP.baseDN3}"
            p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
            p:userFilter="%{idp.authn.LDAP.userFilter}"
            p:connectionFactory-ref="adBindSearchPooledConnectionFactory" />
        <bean id="adDnResolver4" class="org.ldaptive.auth.PooledSearchDnResolver"
            p:baseDn="%{idp.authn.LDAP.baseDN4}"
            p:subtreeSearch="%{idp.authn.LDAP.subtreeSearch:false}"
            p:userFilter="%{idp.authn.LDAP.userFilter}"
            p:connectionFactory-ref="adBindSearchPooledConnectionFactory" />
    <!-- Define Directory1 Search-pool -->
        <bean id="adBindSearchPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
            p:connectionPool-ref="adBindSearchConnectionPool" />
        <bean id="adBindSearchConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool"
            parent="adConnectionPool"
            p:connectionFactory-ref="adBindSearchConnectionFactory"
            p:name="adSearch-pool" />
        <bean id="adBindSearchConnectionFactory" class="org.ldaptive.DefaultConnectionFactory"
            p:connectionConfig-ref="adBindSearchConnectionConfig" />
        <bean id="adBindSearchConnectionConfig"
            parent="adConnectionConfig"
            p:connectionInitializer-ref="adBindConnectionInitializer" />
        <bean id="adBindConnectionInitializer" class="org.ldaptive.BindConnectionInitializer"
            p:bindDn="%{idp.authn.LDAP.bindDN}">
            <property name="bindCredential">
                <bean class="org.ldaptive.Credential">
                    <constructor-arg value="%{idp.authn.LDAP.bindDNCredential}" />
                </bean>
            </property>
        </bean>
        <util:map id="adAuthHandlers">
            <entry key="directory_filter1" value-ref="adAuthHandler1" />
            <entry key="directory_filter2" value-ref="adAuthHandler1" />
            <entry key="directory_filter3" value-ref="adAuthHandler1" />
            <entry key="directory_filter4" value-ref="adAuthHandler1" />
        </util:map>
    <!-- authentication handler for Directory DN resolver -->
        <bean id="adAuthHandler1" class="org.ldaptive.auth.PooledBindAuthenticationHandler"
            p:connectionFactory-ref="adBindPooledConnectionFactory" />
        <bean id="adBindPooledConnectionFactory" class="org.ldaptive.pool.PooledConnectionFactory"
            p:connectionPool-ref="adBindConnectionPool" />
        <bean id="adBindConnectionPool" class="org.ldaptive.pool.BlockingConnectionPool"
            parent="adConnectionPool"
            p:connectionFactory-ref="adBindConnectionFactory"
            p:name="adBind-pool" />
        <bean id="adBindConnectionFactory" class="org.ldaptive.DefaultConnectionFactory"
            p:connectionConfig-ref="adBindConnectionConfig" />
        <bean id="adBindConnectionConfig"
            parent="adConnectionConfig" />
    
    
  2. Now we have to add the additional baseDN attributes that we defined and assign the other values in ldap.properties.

    Attribute Matching

    Note that we match on the attribute "mail" because of our structure, but I think most AD users would want to match on sAMAccountName if you want to match on just "username". If you'd rather match on "username@domain.com" then use userPrincipalName. Also we have idp.authn.LDAP.subtreeSearch set to false because we have OU's we dont want searched, but most people enable this.

    ldap.properties
    # LDAP authentication configuration, see authn/ldap-authn-config.xml
    # Note, this doesn't apply to the use of JAAS
    ## Authenticator strategy, either anonSearchAuthenticator,
    bindSearchAuthenticator, directAuthenticator, adAuthenticator
    idp.authn.LDAP.authenticator = adAggregateAuthenticator
    ## Connection properties ##
    idp.authn.LDAP.ldapURL = ldaps://ad1.skool.edu:636 ldaps://ad2.skool.edu:636
    idp.authn.LDAP.useStartTLS = false
    idp.authn.LDAP.useSSL = true
    idp.authn.LDAP.connectTimeout = 3000
    ## SSL configuration, either jvmTrust, certificateTrust, or keyStoreTrust
    idp.authn.LDAP.sslConfig = certificateTrust
    ## If using certificateTrust above, set to the trusted certificate's path
    idp.authn.LDAP.trustCertificates = %{idp.home}/credentials/ldapserver.crt
    ## If using keyStoreTrust above, set to the truststore path
    idp.authn.LDAP.trustStore = %{idp.home}/credentials/ldapserver.truststore
    ## Return attributes during authentication
    ## NOTE: there is a separate property used for attribute resolution
    idp.authn.LDAP.returnAttributes = passwordExpirationTime,loginGraceRemaining
    ## DN resolution properties ##
    # Search DN resolution, used by anonSearchAuthenticator,bindSearchAuthenticator
    # for AD: CN=Users,DC=example,DC=org
    #
    idp.authn.LDAP.baseDN1 = OU=folder1,DC=skool,DC=edu
    idp.authn.LDAP.baseDN2 = OU=subfolder1,OU=folder2,DC=skool,DC=edu
    idp.authn.LDAP.baseDN3 = OU=folder3,DC=skool,DC=edu
    idp.authn.LDAP.baseDN4 = OU=folder4,DC=skool,DC=edu
    idp.authn.LDAP.subtreeSearch = false
    #idp.authn.LDAP.userFilter = (uid={user})
    idp.authn.LDAP.userFilter = (mail={user})
    # bind search configuration
    # for AD: idp.authn.LDAP.bindDN=adminuser@domain.com
    idp.authn.LDAP.bindDN = CN=ADadmin,ou=managers,dc=skool,dc=edu
    idp.authn.LDAP.bindDNCredential = secretsquirrel66!!!
    # Format DN resolution, used by directAuthenticator, adAuthenticator
    # for AD use idp.authn.LDAP.dnFormat=%s@domain.com
    idp.authn.LDAP.dnFormat = uid=%s,ou=people,dc=example,dc=org
    # LDAP attribute configuration, see attribute-resolver.xml
    # Note, this likely won't apply to the use of legacy V2 resolver configurations
    idp.attribute.resolver.LDAP.ldapURL = %{idp.authn.LDAP.ldapURL}
    idp.attribute.resolver.LDAP.baseDN1 = %{idp.authn.LDAP.baseDN1:undefined}
    idp.attribute.resolver.LDAP.baseDN2 = %{idp.authn.LDAP.baseDN2:undefined}
    idp.attribute.resolver.LDAP.baseDN3 = %{idp.authn.LDAP.baseDN3:undefined}
    idp.attribute.resolver.LDAP.baseDN4 = %{idp.authn.LDAP.baseDN4:undefined}
    idp.attribute.resolver.LDAP.bindDN = %{idp.authn.LDAP.bindDN:undefined}
    idp.attribute.resolver.LDAP.bindDNCredential = %{idp.authn.LDAP.bindDNCredential:undefined}
    idp.attribute.resolver.LDAP.useStartTLS = %{idp.authn.LDAP.useStartTLS:true}
    idp.attribute.resolver.LDAP.trustCertificates = %{idp.authn.LDAP.trustCertificates:undefined}
    #idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal)
    idp.attribute.resolver.LDAP.searchFilter = (mail=$requestContext.principalName)
    idp.attribute.resolver.LDAP.returnAttributes = givenname,mail,samaccountname,sn
    
    
  3.  You should be able to login to test sites with your additional OU's now, but if your not seeing attributes released its because if you use the example attribute-resolver-ldap.xml for your attribute-resolver.xml file then there's only 1 DataConnector defined by default, and you have 4 (or more) DataConnectors. We'll replace the existing DataConnector with multiple DataConnectors in a failover

    attribute-resolver.xml
       <resolver:DataConnector id="myLDAP" xsi:type="dc:LDAPDirectory"
            ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
            baseDN="%{idp.attribute.resolver.LDAP.baseDN1}" 
            principal="%{idp.attribute.resolver.LDAP.bindDN}"
            principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
            noResultIsError="True"
            useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}">
    
            <resolver:FailoverDataConnector ref="myLDAP2" />
    
            <dc:FilterTemplate>
                <![CDATA[
                    %{idp.attribute.resolver.LDAP.searchFilter}
                ]]>
            </dc:FilterTemplate>
            <dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes>
            <dc:LDAPProperty name="java.naming.referral" value="follow"/>
            <dc:StartTLSTrustCredential id="LDAPtoIdPCredential" xsi:type="sec:X509ResourceBacked">
                <sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate>
            </dc:StartTLSTrustCredential>
    
        </resolver:DataConnector>
    
        <resolver:DataConnector id="myLDAP2" xsi:type="dc:LDAPDirectory"
            ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
            baseDN="%{idp.attribute.resolver.LDAP.baseDN2}" 
            principal="%{idp.attribute.resolver.LDAP.bindDN}"
            principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
            noResultIsError="True"
            useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}">
    
            <resolver:FailoverDataConnector ref="myLDAP3" />
    
            <dc:FilterTemplate>
                <![CDATA[
                    %{idp.attribute.resolver.LDAP.searchFilter}
                ]]>
            </dc:FilterTemplate>
            <dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes>
            <dc:LDAPProperty name="java.naming.referral" value="follow"/>
            <dc:StartTLSTrustCredential id="LDAPtoIdPCredential" xsi:type="sec:X509ResourceBacked">
                <sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate>
            </dc:StartTLSTrustCredential>
    
        </resolver:DataConnector>
    
        <resolver:DataConnector id="myLDAP3" xsi:type="dc:LDAPDirectory"
            ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
            baseDN="%{idp.attribute.resolver.LDAP.baseDN3}" 
            principal="%{idp.attribute.resolver.LDAP.bindDN}"
            principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
            noResultIsError="True"
            useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}">
    
            <resolver:FailoverDataConnector ref="myLDAP4" />
    
            <dc:FilterTemplate>
                <![CDATA[
                    %{idp.attribute.resolver.LDAP.searchFilter}
                ]]>
            </dc:FilterTemplate>
            <dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes>
            <dc:LDAPProperty name="java.naming.referral" value="follow"/>
            <dc:StartTLSTrustCredential id="LDAPtoIdPCredential" xsi:type="sec:X509ResourceBacked">
                <sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate>
            </dc:StartTLSTrustCredential>
    
        </resolver:DataConnector>
    
        <resolver:DataConnector id="myLDAP4" xsi:type="dc:LDAPDirectory"
            ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
            baseDN="%{idp.attribute.resolver.LDAP.baseDN4}" 
            principal="%{idp.attribute.resolver.LDAP.bindDN}"
            principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
            noResultIsError="True"
            useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS::true}">
    
            <dc:FilterTemplate>
                <![CDATA[
                    %{idp.attribute.resolver.LDAP.searchFilter}
                ]]>
            </dc:FilterTemplate>
            <dc:ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</dc:ReturnAttributes>
            <dc:LDAPProperty name="java.naming.referral" value="follow"/>
            <dc:StartTLSTrustCredential id="LDAPtoIdPCredential" xsi:type="sec:X509ResourceBacked">
                <sec:Certificate>%{idp.attribute.resolver.LDAP.trustCertificates}</sec:Certificate>
            </dc:StartTLSTrustCredential>
    
        </resolver:DataConnector>