International Attribute Support for SWITCHaai Identity Providers

This guide describes how to extend the affiliation attribute with the member value and how to add six internationally used attributes, which are required by some international Federation Partners (e.g. publishers). SWITCH recommends to add these attributes as they will ensure that users in SWITCHaai can access international services and that international collaboration becomes easier. The latter especially applies for more and more research projects funded by the European Commission and other funding bodies.

The attributes that are recommended to add are:

Display Name
A full name of a user usually consisting of first and last name e.g. John Doe
Common Name
Same as Display Name but can be multi-valued. A full name of a user usually consisting of first and last name e.g. John Doe
Principal name
International version of the swissEduPersonUniqueID attribute e.g. 32498-cwh33ridc-23498@unibas.ch
SCHAC Home Organisation
International version of the swissEduPersonHomeOrganization attribute. Basically, the domain name of an organization
e.g. unige.ch
SCHAC Home Organisation Type
International version of the swissEduPersonHomeOrganizationType attribute e.g. urn:schac:homeOrganizationType:int:universityHospital
(specification incomplete at the moment)
Scoped affiliation
Like the affiliation attribute but with a domain name added e.g. staff@ethz.ch.
This attribute is very often used internationally and required by some publishers.

The information contained in the above attributes is already available for all SWITCHaai Identity Providers. No changes in the Active Directory or LDAP Directory are needed because the above attributes are either the same for all users or they can be composed from already existing attribute values. Therefore, adding these attributes is only a matter of Identity Provider configuration.

Setup

Setup

Before starting the configuration, please complete the following form and click on the "Update" button. This allows generating custom-tailored configuration snippets in the sections below.

Complete this form using AAI Complete Form with AAI
Home Organisation Name
Organisation's domain name,
e.g. epfl.ch, unisi.ch
Home Organisation Type

1. Changes in Resource Registry

In order to release the international attributes, first adapt the Home Organisation description of the Identity Provider in the SWITCH Resource Registry.

This includes the following steps:

  1. Use the International Attribute Wizard
  2. Authenticate with your AAI account for which you have Home Organisation administration privileges and follow the instructions. You will be automatically redirected back to this page after the changes were applied in the Resource Registry.

This will add the above-mentioned international attributes as supported attributes and set the default release scope to Federation for required attributes and Own Organization for desired attributes. This means that the attributes are by default released to all SWITCHaai services if they are required by a service. The attributes are however only released to services of the own organisation if they are just desired. Of course, this default policy can be changed in the Resource Registry.

Note

All changes of the Attribute Release Policy will only become active when the Identity Provider downloads the attribute-filter.xml the next time from the Resource Registry. This may take up to one hour. The Resource Registry will send an email containing all changes to the administrative contacts of the Home Organisation when the attribute-filter.xml is downloaded.

2. Configure Attribute Resolver

The goal of the following steps is to configure the Identity Provider to release the International attributes declared as supported in the previous step. All these attributes are internationally standardized and easy to add because they can be composed of attributes, which are already available at your SWITCHaai Identity Provider.

Performance Considerations

The following attribute definitions partially use JavaScript. We have heard of users having some negative performance influence because of heavy use of such scripts. In case you have a heavily loaded IdP and performance might be an issue for you at all, you should do a performance test of your IdP in a test environment. You find more information about performance testing at the Shibboleth Wiki. In case of questions, ask the AAI Team at aai@switch.ch for assistance.

In order to support the additional attributes, the Shibboleth Identity Provider attribute resolver configuration has to be adapted like this:

  1. Login as root user on the host that runs the Shibboleth Identity Provider that you want to enable for interfederation.
  2. Go to the Shibboleth configuration directory and make a backup of the file attribute-resolver.xml :
    cd /opt/shibboleth-idp/conf/
    cp -p attribute-resolver.xml attribute-resolver.xml.bak
    The backup file allows you to fall back to the current state of the Identity Provider in case something goes wrong.
  3. Open the file attribute-resolver.xml in a text editor.
  4. Search the definition for the multi-valued attribute eduPersonAffiliation. This attribute should be extended such that users who have one of the following values set, should also have the additional value member:
    • student
    • staff
    • faculty
    • employee (not used in SWITCHaai)
    Assuming that the affilation values for users are set in your user directory, you probably find a definition like the following:
        <!-- Affiliation (eduPersonAffiliation) -->
        <resolver:AttributeDefinition id="eduPersonAffiliation" xsi:type="ad:Simple" sourceAttributeID="eduPersonAffiliation">
            <resolver:Dependency ref="myLDAP" />
            <resolver:AttributeEncoder xsi:type="enc:SAML2String"
                name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" friendlyName="eduPersonAffiliation" />
        </resolver:AttributeDefinition>
    
    There are two options to add the member value: Either it is added to the user directory for each user individually, which is not only a one-time change but also is likely to affect the processes to register a new user. Or the member value is added by the Identity Provider based on the already available affiliation values.
    In case you don't want to extend the user directory and set the member value for each user, replace the existing definition with the following AttributeDefinition that will set the member value programmatically:
        <!-- Affiliation (eduPersonAffiliation) -->
        <resolver:AttributeDefinition xsi:type="ad:Mapped" id="eduPersonAffiliation" sourceAttributeID="eduPersonAffiliation">
            <resolver:Dependency ref="myLDAP" />
    
            <resolver:DisplayName xml:lang="en">Affiliation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Zugehörigkeit</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Affiliation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Tipo di membro</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                Affiliation: Type of affiliation with Home Organization</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Art der Zugehörigkeit zur Heimorganisation</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Type d'affiliation dans l'organisation</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">
                Tipo di membro: Tipo di lavoro svolto per l'organizzazione.
            </resolver:DisplayDescription>
    
            <resolver:AttributeEncoder xsi:type="enc:SAML1String"
                name="urn:mace:dir:attribute-def:eduPersonAffiliation" />
            <resolver:AttributeEncoder xsi:type="enc:SAML2String"
                name="urn:oid:1.3.6.1.4.1.5923.1.1.1.1" friendlyName="eduPersonAffiliation" />
            <ad:DefaultValue passThru="true"/>
            <ad:ValueMap>
                <ad:ReturnValue>member</ad:ReturnValue>
                <ad:SourceValue>staff|student|faculty|employee</ad:SourceValue>
            </ad:ValueMap>
            <ad:ValueMap>
                <ad:ReturnValue>$1</ad:ReturnValue>
                <ad:SourceValue>(staff|student|faculty|employee)</ad:SourceValue>
            </ad:ValueMap>
        </resolver:AttributeDefinition>
    
    Ensure that the Dependency is set correctly to the data connector that is used to get user attributes from. The default is myLDAP. The DisplayName and DisplayDescription elements are used in case your Identity Provider uses uApprove. Also note that if you already use a Script to set the affiliation value programmatically, you will have to adapt your existing script by adding the above if-clause as last statement.
  5. The next step is to add new attribute definitions for:
    • Common Name (commonName)
    • Display Name (displayName)
    • Principal name (eduPersonPrincipalName)
    • SCHAC Home Organisation (schacHomeOrganization)
    • SCHAC Home Organisation Type (schacHomeOrganizationType)
    • Scoped Affiliation (eduPersonScopedAffiliation)

    To support these attribute, add the following XML snippets just after the last already existing <AttributeDefinition> element.

    Alternative Definitions

    For some attributes, we provide two alternative definitions, depending on whether the source attribute is already available in your user directory or not (like e.g. commonName or displayName). In case the source attribute is not contained in the user directory, the attribute value is composed by other existing attributes by using JavaScript. Just use the definition that best matches your setup.

    
        <!-- Common Name (commonName) -->
        <!-- Attribute commonName is contained in your LDAP directory: use the value from the LDAP directory -->
        <!--
        <resolver:AttributeDefinition id="commonName" xsi:type="ad:Simple" sourceAttributeID="cn">
            <resolver:Dependency ref="myLDAP" />
            
            <resolver:DisplayName xml:lang="en">Common Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Nom</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Nome</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                One or more names that should appear in white-pages-like applications for this person.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Name</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Nom</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">Nome</resolver:DisplayDescription>
                
            <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:2.5.4.3" friendlyName="cn" />
        </resolver:AttributeDefinition>
        -->
        <!-- Attribute commonName is not contained in your LDAP directory: Use the value of the attribute displayName -->
        <resolver:AttributeDefinition id="commonName" xsi:type="ad:Simple" sourceAttributeID="displayName">
            <resolver:Dependency ref="displayName" />
            
            <resolver:DisplayName xml:lang="en">Common Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Nom</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Nome</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                One or more names that should appear in white-pages-like applications for this person.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Name</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Nom</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">Nome</resolver:DisplayDescription>
                
            <resolver:AttributeEncoder xsi:type="enc:SAML2String" name="urn:oid:2.5.4.3" friendlyName="cn" />
        </resolver:AttributeDefinition>
    
        <!-- Display Name (displayName) -->
        <!-- Attribute displayName is contained in your LDAP directory: use the value from the LDAP directory -->
        <!--
        <resolver:AttributeDefinition id="displayName" xsi:type="ad:Simple" sourceAttributeID="displayName">
            <resolver:Dependency ref="myLDAP" />
            
            <resolver:DisplayName xml:lang="en">Display Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Anzeigename</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Nom</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Nome</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                The name that should appear in white-pages-like applications for this person.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Anzeigename</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Nom</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">Nome</resolver:DisplayDescription>
                
            <resolver:AttributeEncoder xsi:type="enc:SAML2String" 
                name="urn:oid:2.16.840.1.113730.3.1.241" friendlyName="displayName" />
        </resolver:AttributeDefinition>
        -->
        <!-- Attribute displayName is not contained in your LDAP directory: compose the value with JavaScript -->
        <resolver:AttributeDefinition id="displayName" xsi:type="ad:Script">
            <resolver:Dependency ref="givenName" />
            <resolver:Dependency ref="surname" />
            
            <resolver:DisplayName xml:lang="en">Display Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Anzeigename</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Nom</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Nome</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                The name that should appear in white-pages-like applications for this person.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Anzeigename</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Nom</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">Nome</resolver:DisplayDescription>
                
            <resolver:AttributeEncoder xsi:type="enc:SAML2String" 
                name="urn:oid:2.16.840.1.113730.3.1.241" friendlyName="displayName" />
                
            <ad:Script>
              <![CDATA[
                importPackage(Packages.edu.internet2.middleware.shibboleth.common.attribute.provider);
    
                // This implementation composes the value of the attribute displayName
                // from the values of the attributes givenName and surname.
    
                // Initialize displayName
                displayName = new BasicAttribute("displayName");
    
                // compose value from givenName and surname
    
                // check whether givenName and surname exist
                if (givenName != null && givenName.getValues().size() > 0) {
                  gn = givenName.getValues().get(0);
                } else {
                  gn = null;
                }
                if (surname != null && surname.getValues().size() > 0) {
                  sn = surname.getValues().get(0);
                } else {
                  sn = null;
                }
    
                if (sn != null && gn != null) {
                  displayName.getValues().add( gn + " " + sn );
                } else if (sn != null) {
                  displayName.getValues().add( sn );
                } else if (gn != null) {
                  displayName.getValues().add( gn );
                }
              ]]>
            </ad:Script>
        </resolver:AttributeDefinition>
    
        <!-- Principal name (eduPersonPrincipalName) -->
        <!-- Use the same value as the attribute swissEduPersonUniqueID -->
        <resolver:AttributeDefinition id="eduPersonPrincipalName" xsi:type="ad:Simple"
            sourceAttributeID="swissEduPersonUniqueID">
    
            <resolver:Dependency ref="swissEduPersonUniqueID" />
            
            <resolver:DisplayName xml:lang="en">Principal Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Principal Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Principal Name</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Principal Name</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                A unique identifier for a person, mainly for inter-institutional user identification.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">
                Eindeutige Benützeridentifikation
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">
                L'identifiant unique de l'utilisateur au seins de l'AAI.
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">
                Un ID personale che identifica chiaramente l'utente in seno alla sua organizzazione
            </resolver:DisplayDescription>
    
            <resolver:AttributeEncoder xsi:type="enc:SAML2String"
                name="urn:oid:1.3.6.1.4.1.5923.1.1.1.6" friendlyName="eduPersonPrincipalName" />
        </resolver:AttributeDefinition>
    
        <!-- SCHAC Home Organisation (schacHomeOrganization) -->
        <resolver:AttributeDefinition id="schacHomeOrganization" xsi:type="ad:Simple"
            sourceAttributeID="schacHomeOrganization">
    
            <resolver:Dependency ref="staticAttributes" />
            
            <resolver:DisplayName xml:lang="en">Home organization</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Heimorganisation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Organisation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Nome dell'organizzazione</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                Home Organization: Domain name of a Home Organization
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">
                Domain Name der Heimorganisation
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">
                Nom de domaine de l'organisation: uzh.ch, unil.ch, ...
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">
                Nome dell'organizzazione come per esempio: uzh.ch, unil.ch, ...
            </resolver:DisplayDescription>
            
            <resolver:AttributeEncoder xsi:type="enc:SAML2String"
                name="urn:oid:1.3.6.1.4.1.25178.1.2.9"
                friendlyName="schacHomeOrganization" />
        </resolver:AttributeDefinition>
    
        <!-- SCHAC Home Organisation Type (schacHomeOrganizationType) -->
        <!-- first value:  swissEduPersonHomeOrganizationType attribute prefixed by "urn:schac:homeOrganizationType:ch:"
             second value: an internationally standardized value, where applicable -->
        <resolver:AttributeDefinition id="schacHomeOrganizationType" xsi:type="ad:Mapped" 
            sourceAttributeID="swissEduPersonHomeOrganizationType">
    
            <resolver:Dependency ref="staticAttributes" />
    
            <resolver:DisplayName xml:lang="en">Home organization type (international)</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Typ der Heimorganisation (international)</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Type d'Organisation (international)</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Tipo dell'organizzazione di appartenenza (internazionale)</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                Home Organization Type: Type of a Home Organization
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">Kategorie der Heimorganisation</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">Le type d'organisation</resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">Tipo dell'organizzazione di appartenenza</resolver:DisplayDescription>
    
            <resolver:AttributeEncoder xsi:type="enc:SAML1String"
                name="urn:mace:terena.org:schac:schacHomeOrganizationType" />
            <resolver:AttributeEncoder xsi:type="enc:SAML2String"
                name="urn:oid:1.3.6.1.4.1.25178.1.2.10"
                friendlyName="schacHomeOrganizationType" />
    
            <ad:ValueMap>
                <ad:ReturnValue>urn:schac:homeOrganizationType:ch:$1</ad:ReturnValue>
                <ad:SourceValue>(.+)</ad:SourceValue>
            </ad:ValueMap>
            <ad:ValueMap>
                <ad:ReturnValue>urn:schac:homeOrganizationType:eu:higherEducationalInstitution</ad:ReturnValue>
                <ad:SourceValue>university|uas|tertiaryb</ad:SourceValue>
            </ad:ValueMap>
            <ad:ValueMap>
                <ad:ReturnValue>urn:schac:homeOrganizationType:eu:educationalInstitution</ad:ReturnValue>
                <ad:SourceValue>uppersecondary</ad:SourceValue>
            </ad:ValueMap>
        </resolver:AttributeDefinition>
        
        <!-- Scoped affiliation (eduPersonScopedAffiliation) -->
        <resolver:AttributeDefinition id="eduPersonScopedAffiliation" xsi:type="ad:Scoped"
            scope="####YOUR_ORGANIZATION_DOMAIN_NAME###" sourceAttributeID="eduPersonAffiliation">
        
            <resolver:Dependency ref="eduPersonAffiliation" />
            
            <resolver:DisplayName xml:lang="en">Affiliation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="de">Zugehörigkeit</resolver:DisplayName>
            <resolver:DisplayName xml:lang="fr">Affiliation</resolver:DisplayName>
            <resolver:DisplayName xml:lang="it">Tipo di membro</resolver:DisplayName>
            <resolver:DisplayDescription xml:lang="en">
                Affiliation: Type of affiliation with Home Organization
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="de">
                Art der Zugehörigkeit zur Heimorganisation
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="fr">
                Type d'affiliation dans l'organisation
            </resolver:DisplayDescription>
            <resolver:DisplayDescription xml:lang="it">
                Tipo di membro: Tipo di lavoro svolto per l'organizzazione.
            </resolver:DisplayDescription>
            
            <resolver:AttributeEncoder xsi:type="enc:SAML2ScopedString" 
                name="urn:oid:1.3.6.1.4.1.5923.1.1.1.9" friendlyName="eduPersonScopedAffiliation" />
        </resolver:AttributeDefinition>
    
        
    The above snippets will add attribute definitions of all attributes that are recommended to support. Make sure that the scope of the eduPersonScopedAffiliation is set to your organization's domain name (e.g. ethz.ch, unige.ch, phlu.ch, ...).

    Note

    Some of the above attribute definitions make use of Scripted Attributes. More information about Scripted Attributes can be found at the Script Attribute page in the Shibboleth wiki.
  6. Attributes like the schacHomeOrganization and schacHomeOrganizationType from above are the same for all users of the Identity Provider. Therefore, this attribute can be set using a static data connector in the attribute resolver configuration. There already may be a static data connector defined. Therefore, continue by choosing one of the two options:
    1. If there is already a data connector with id="staticAttributes" in the attribute-resolver.xml insert the following code within the start tags of the existing DataConnector start and end tags:
              <dc:Attribute id="schacHomeOrganization">
                  <dc:Value>####YOUR_ORGANIZATION_DOMAIN_NAME###</dc:Value>
              </dc:Attribute>
    2. If there is no active data connector with id="staticAttributes" yet in the attribute-resolver.xml file, insert the following code just after an already existing DataConnector:
          <!-- Static Connector -->
          <resolver:DataConnector id="staticAttributes" xsi:type="dc:Static">
              <dc:Attribute id="schacHomeOrganization">
                  <dc:Value>####YOUR_ORGANIZATION_DOMAIN_NAME###</dc:Value>
              </dc:Attribute>
          </resolver:DataConnector>

    Note

    You find more information on static data connector page in the Shibboleth wiki.
  7. Save the file and exit the text editor

Restart and Check Identity Provider

The Identity Provider should now be ready to restart:

  1. Check that the edited XML files are still well-formed. For instance with:
    xmlwf attribute-resolver.xml
    
    If no output is shown, the configuration files are well-formed. Alternatively, it is also possible to open the files in Firefox, which will display a warning message if a file is not well-formed.
  2. If you are confident that the configuration is correct and that the short service disruption of the Identity Provider restart won't cause problems, restart the Identity Provider by restarting the servlet container (e.g. Tomcat). For instance with:
    $ /etc/init.d/tomcat* restart
  3. Inspect the Shibboleth log file during startup e.g. with the command:
    $ tail -f /var/log/shibboleth/idp-process.log
    Check that there are no ERROR, CRIT or WARN messages during startup. If there are, you might want to restart the Identity Provider again with the backup version of attribute-resolver.xml

3. Attribute Test

In order to ensure that the Identity Provider configuration was applied correctly, perform the following test:

  1. Access the Interfederation Attribute Test page and authenticate with AAI
  2. If the following page looks like on the screenshot below, something is not yet working correctly:
    'test failed' screenshot
    Contact aai@switch.ch for assistance if you have questions or if there is a problem that you cannot solve on your own.
  3. In order to pass the test, you should see a page like below:
    'test passed' screenshot
    Congratulations, if you see the above "Passed" logo, the Identity Provider supports the new attributes.

4. Troubleshooting

This section lists some common problems and possible solutions.

The test is not passed
You may have to wait 1 hour after creating the specific Attribute Release Policy rule until this change is downloaded by your Identity Provider.
Another error not listed above
Please have a look at the Common Identity Provider Errors page of the Shibboleth Wiki. If you don't find an error description that matches yours, contact the AAI team.

5. References