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.
dn
or distinguishedName
attribute.InputDataConnector
element referencing the existing one.
(member:1.2.840.113556.1.4.1941:=${attributename.get(0)})
maxResultsSize="0"
)<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> |
<!-- 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> |
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.
<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> |