SAML Attribute query

Some time before or at latest when an organisation is migrating to the SWITCH edu-ID, its Identity Provider (IdP) must support SAML attribute queries coming from the edu-ID service to link user accounts with their organisation and to maintain those affiliations up-to-date. SAML Attribute queries from edu-ID service use the swissEduPersonUniqueID attribute as identifier (SAML NameID). This requires a small configuration change on the Shibboleth IdP so it can respond to queries using this identifier. This page describes the necessary changes to implement this special configuration.

Configuration

  1. In file /opt/shibboleth-idp/conf/c14n/subject-c14n.xml:
    1. Add the OID of the attribute swissEduPersonUniqueID attribute to the list bean shibboleth.NameTransformFormats.
      Note: It's recommended to disable or remove other existing entries, except you have some use case for them.
    2. Add the entityID values of SPs allowed to send attribute queries with a swissEduPersonUniqueID value as NameID to the bean shibboleth.NameTransformPredicate.
      The two entityIDs mentioned below are used by edu-ID systems.
      ...
      <!--
      What SAML NameID formats do you want to support direct transformations for?
      -->
      <util:list id="shibboleth.NameTransformFormats">
      <!-- swissEduPersonUniqueID -->
      <value>urn:oid:2.16.756.1.2.5.1.1.1</value> </util:list> <!-  Under what conditions should direct NameID mapping be allowed? By default, never. Any condition can be used here; the example is suitable for enumerating a number of SPs to allow. --> <bean id="shibboleth.NameTransformPredicate"
      parent="shibboleth.Conditions.RelyingPartyId"> <constructor-arg name="candidates">
      <!--
      Enable the SWITCH edu-ID SPs to do attribute queries using the
      attribute "swissEduPersonUniqueID" as identifier (i.e. NameID).
      The URN of the attribute must be listed in
      "shibboleth.NameTransformFormats".
      -->
      <list> <value>https://eduid.ch/shibboleth</value> <!-- Comment out the line below once in production --> <value>https://test.eduid.ch/shibboleth</value> </list> </constructor-arg> </bean> ...
  2. In file /opt/shibboleth-idp/conf/ldap.properties:
    Modify the attribute resolver LDAP filter to also search for entries by swissEduPersonUniqueID (or whatever field is used to store the value of the swissEduPersonUniqueID identifier attribute).
    Note: If this attribute is not stored as field in your user directory but is generated by the IdP on the fly, please get in touch with SWITCH to discuss how to solve it.
    E.g. from:
    idp.attribute.resolver.LDAP.searchFilter = (uid=$resolutionContext.principal)

    modify it to:
    idp.attribute.resolver.LDAP.searchFilter = (|(uid=$resolutionContext.principal)(swissEduPersonUniqueID=$resolutionContext.principal))
    

 

Important: To make sure the that the attribute query doesn't return attributes of deactivated users, follow the instructions in the section Handling deactivated users below.

 

Testing

In order to test that an IdP is correctly configured, you can use the attribute resolver handler of an authorized Shibboleth SP to send an attribute query with a swissEduPersonUniqueId. Note the parameters:

  • format is the OID of the swissEduPersonUniqueId attribute
  • entityID is the IdP to test
  • nameId is the swissEduPersonUniqueId to look up.
curl --get "https://test.eduid.ch/Shibboleth.sso/AttributeQuery" \
--data-urlencode "format=urn:oid:2.16.756.1.2.5.1.1.1" \
--data-urlencode "entityID=https://test.idph.switch.ch/idp/shibboleth" \
--data-urlencode "nameId=7622788@example.org"

If the query is successful, the output will contain personal attributes belonging to the searched account.

{
  "surname": [
    "Staff" 
  ],
  "givenName": [
    "Test3" 
  ],
  "mail": [
    "test3.staff@example.org" 
  ],
  "affiliation": [
    "member",
    "staff" 
  ],
  "homeOrganization": [
    "test.idph.switch.ch" 
  ],
  "uniqueID": [
    "7622788@example.org" 
  ],
  ...
}

Handling deactivated users

As the attribute resolution on the IdP doesn't involve user authentication, you need to make sure that an attribute query doesn't return attributes for deactivated users.

How this can be handled depends on the structure of your user directory.

Case 1: Deactivating a user object just modifies a flag in the user's directory record.

This case applies to Active Directory.

In this case, you need to extend the LDAP search filter in your IdP's attribute resolver configuration such that the status of the user object is checked.

For Active Directory, you need to check the status of the attribute userAccountControl.

Example (adapt it to your current search filter as required):

Adapt the Attribute Resolver's search filter in the file /opt/shibboleth-idp/conf/ldap.properties:

idp.attribute.resolver.LDAP.searchFilter = (&(sAMAccountName=$resolutionContext.principal)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))

Case 2: Deactivating a user object moves it to another branch in the LDAP tree

If the branch of deactivated users is outside the base DN, you don't need to change anything, as deactivated users are not found during attribute resolution.

Otherwise, you need to find a suitable criterion, similar as in case 1.