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.
Ensure your existing LDAP Data Connector provides the
dn
ordistinguishedName
attribute.Create a new LDAP Data Connector with an
InputDataConnector
element referencing the existing one.Set the search filter to
(member:1.2.840.113556.1.4.1941:=${attributename.get(0)})
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"
)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>
</AttributeDefinition>