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.

LDAPNestedGroups

Largely based on work by Vladimir Mencl, Tuakiri Federation, New Zealand (ResolverScriptAttributeDefinitionExamples).

Active Directory and other LDAP directories support the ability to make one group a member of another and nest them. The directories usually, however, only return a memberOf attribute with the groups that the user is directly a member of and don't "resolve" those memberships unless asked specifically using a LDAP filter flag.

This is achieved by asking the directory for all the groups a given user (by distinguished name) is a member of but this needs a second LDAP query for which we need a second DataConnector which takes, as its input, the DN of the resolved user object.

  1. Ensure your existing LDAP Data Connector provides the dn or distinguishedName attribute.
  2. Create a new LDAP Data Connector with an InputDataConnector element referencing the existing one.
  3. Set the search filter to (member:1.2.840.113556.1.4.1941:=${attributename.get(0)})
  4. The results of the search will be a set of Group objects so tell the data connector it can have any number of responses (maxResultsSize="0")
  5. The attributes returned will be collated into a set and made available to the resolver.

Data Connector

Existing data connector (example)

Example existing data connector
<DataConnector id="ldap" xsi:type="LDAPDirectory"
    ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
    baseDN="%{idp.attribute.resolver.LDAP.baseDN}"
    principal="%{idp.attribute.resolver.LDAP.bindDN}"
    principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
    trustFile="%{idp.attribute.resolver.LDAP.trustCertificates}"
    useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS}" >

    <FilterTemplate>
        <![CDATA[
            %{idp.attribute.resolver.LDAP.searchFilter}
        ]]>
    </FilterTemplate>

    <ReturnAttributes>%{idp.attribute.resolver.LDAP.returnAttributes}</ReturnAttributes>

</DataConnector>

New data connector

New nested group resolver
<!-- Resolve nested groups in AD using the DN of the resolved user -->
<DataConnector id="ldap-groups" xsi:type="LDAPDirectory"
    ldapURL="%{idp.attribute.resolver.LDAP.ldapURL}"
    baseDN="%{idp.attribute.resolver.LDAP.baseDN}"
    principal="%{idp.attribute.resolver.LDAP.bindDN}"
    principalCredential="%{idp.attribute.resolver.LDAP.bindDNCredential}"
    useStartTLS="%{idp.attribute.resolver.LDAP.useStartTLS}"
    maxResultSize="0">

    <InputDataConnector ref="ldap" attributeNames="distinguishedName" />

    <FilterTemplate>
        <![CDATA[
            (member:1.2.840.113556.1.4.1941:=$distinguishedName.get(0))
        ]]>
    </FilterTemplate>

    <ReturnAttributes>
        distinguishedName
        sAMAccountName
    </ReturnAttributes>
</DataConnector>



Attribute definition

You now have two (probably multi-valued) attributes available to use. For example you could map them into an affiliation or turn them into entitlements.

Example attribute definition
<AttributeDefinition xsi:type="Mapped" id="eduPersonAffiliation">
    <InputDataConnector ref="ldap-groups" attributeNames="distinguishedName" />
    <DefaultValue passThru="false"/>
    <ValueMap>
        <ReturnValue>student</ReturnValue>
        <SourceValue>CN=All Students,OU=Groups,DC=example,DC=ac,DC=uk</SourceValue>
    </ValueMap>
    <ValueMap>
        <ReturnValue>staff</ReturnValue>
        <SourceValue>CN=All Staff,OU=Groups,DC=example,DC=ac,DC=uk</SourceValue>
    </ValueMap>
    <ValueMap>
        <ReturnValue>member</ReturnValue>
        <SourceValue>CN=All Students,OU=Groups,DC=example,DC=ac,DC=uk</SourceValue>
        <SourceValue>CN=All Staff,OU=Groups,DC=example,DC=ac,DC=uk</SourceValue>
    </ValueMap>

    <AttributeEncoder xsi:type="SAML2String" name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" encodeType="false"/>
 </AttributeDefinition>