Sonderfälle bei Generierung und Weitergabe der Persistent ID

Zur Persistent ID allgemein siehe unter Storage und Persistent Identifier.

Beispiel der Hochschule Bremen zur Generierung des Quellattributes zur persistentId mithilfe von „uid“ und „uidNumber“:

attribute-resolver.xml
 <AttributeDefinition xsi:type="ScriptedAttribute" id="uniqueIdentifier" >
    <InputAttributeDefinition ref="uid" />       
    <InputAttributeDefinition ref="uidNumber" />       
    <Script>
            <![CDATA[
     	            uid= uid.getValues().get(0);
      	            uidNumber = uidNumber.getValues().get(0);
       	            stringUidNumber = String(uidNumber);
                    newIdentifier = uid+stringUidNumber;
                    uniqueIdentifier.getValues().add(newIdentifier);
           ]]>       
    </Script>
</AttributeDefinition>

Sofern Sie die persistendId nicht pauschal an alle SPs weitergeben wollen, kann dies in einem RelyingPartyOverride definiert werden.

Dazu muss Folgendes gemacht werden:

  • im Default-Block wird nur die TransientId freigegeben
  • einen Override definieren, in dem für gewisse EntityIds die persistentId freigegeben wird
relying-party.xml
<beans ...>
  <!-- ... -->
  <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
    <property name="profileConfigurations">
       <list>
         <bean parent="Shibboleth.SSO" 
               p:postAuthenticationFlows="#{{'terms-of-use', 'attribute-release'}}" />
         <!-- ... -->
         <bean parent="SAML2.SSO" 
               p:postAuthenticationFlows="#{{'terms-of-use', 'attribute-release'}}" 
               p:nameIDFormatPrecedence="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" />
         <!-- ... -->
        </list>
    </property>
  </bean>
  <util:list id="shibboleth.RelyingPartyOverrides">
     <!-- ... -->
     <!-- komma-separierte Liste der Entity IDs der berechtigten SPs, hier inkl. DFNConf -->
     <bean parent="RelyingPartyByName" 
         c:relyingPartyIds="#{{'https://testsp3.aai.dfn.de/shibboleth', 'https://testsp2.aai.dfn.de/shibboleth', 'https://webconf.vc.dfn.de/shibboleth', 'https://my.conf.dfn.de/shibboleth', 'https://self.conf.dfn.de/shibboleth', 'https://www.conf.dfn.de/shibboleth'}}">
         <property name="profileConfigurations">
           <list>
             <bean parent="SAML2.SSO" 
                   p:postAuthenticationFlows="#{{'terms-of-use', 'attribute-release'}}"
                   p:nameIDFormatPrecedence="#{{'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'}}" />
              <ref bean="SAML2.Logout" />
              <ref bean="SAML2.AttributeQuery" />
              <ref bean="SAML2.ArtifactResolution" />
           </list>
         </property>
     </bean>
  </util:list>
</beans>

Möchte man die Freigabe der persistentId analog zu Attribut-Filterregeln weiter einschränken, sind mehrere Schritte nötig.

Man kann zwar mit Hilfe von ActivationConditions die NameIDGeneration einschränken, jedoch existiert zu diesem Zeitpunkt noch kein AttributContext. Man kann deshalb in der /conf/relying-party.xml keine Abhängigkeit zu anderen Attributen abbilden: Diese werden erst nach dem Login der Nutzer*innen ausgelesen.

Um die persistentId dennoch nur dann an einen SP auszuliefern, wenn Nutzer*innen z.B. ein bestimmtes Entitlement haben, muss man wie folgt vorgehen:

  1. globale Freigabe der persistentID für den SP:
    /conf/relying-party.xml
    <!-- ... -->
     
    <util:list id="shibboleth.RelyingPartyOverrides">
            <bean parent="RelyingPartyByName" c:relyingPartyIds="#{{
                    'https://e5.onthehub.com'
                    }}">
     
                    <property name="profileConfigurations">
                            <list>
                                    <bean parent="SAML2.SSO" p:postAuthenticationFlows="attribute-release"
                                            p:nameIDFormatPrecedence="#{{'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent', 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'}}" />
                                    <ref bean="SAML2.Logout" />
                                    <ref bean="SAML2.AttributeQuery" />
                                    <ref bean="SAML2.ArtifactResolution" />
                            </list>
                    </property>
            </bean>
     
    <!-- ... -->
  2. Definition einer Condition mit allen Anforderungen an ein Attribut und Referenzierung als Abhängigkeit bei der Generierung der persistentID:
    /system/conf/saml-nameid-system.xml
    <!-- ... -->
     
        <bean id="shibboleth.SAML2PersistentGenerator" lazy-init="true"
                class="net.shibboleth.idp.saml.nameid.impl.PersistentSAML2NameIDGenerator"
                p:useUnfilteredAttributes="%{idp.persistentId.useUnfilteredAttributes:true}"
                p:persistentIdGenerator-ref="#{'%{idp.persistentId.generator:shibboleth.ComputedPersistentIdGenerator}'.trim()}"
                p:activationCondition-ref="dreamspark">
            <property name="attributeSourceIds">
                <bean parent="shibboleth.CommaDelimStringArray" c:_0="#{'%{idp.persistentId.sourceAttribute:}'.trim()}" />
            </property>
        </bean>
     
            <bean id="dreamspark" parent="shibboleth.Conditions.OR">
                    <constructor-arg>
                            <list>
                                    <bean parent="shibboleth.Conditions.NOT">
                                            <constructor-arg>
                                                    <bean parent="shibboleth.Conditions.RelyingPartyId" c:_0="https://e5.onthehub.com" />
                                            </constructor-arg>
                                    </bean>
                                    <bean class="net.shibboleth.idp.profile.logic.SimpleAttributePredicate" p:useUnfilteredAttributes="true">
                                            <property name="attributeValueMap">
                                                    <map>
                                                            <entry key="eduPersonEntitlement">
                                                                    <list>
                                                                            <value>Dreamspark-Premium-User-Wirtschaft</value>
                                                                            <value>Dreamspark-Premium-User-Informatik</value>
                                                                    </list>
                                                            </entry>
                                                    </map>
                                            </property>
                                    </bean>
                            </list>
                    </constructor-arg>
            </bean>
     
    <!-- ... -->

Dadurch ist folgendes Verhalten des IdP konfiguriert: Wenn es sich um den konfigurierten SP handelt und die Nutzer*innen keinen der oben genannten Attribut-Werte aufweisen, dann schlägt die Condition fehl: Es wird keine persistentID generiert. In allen anderen Fällen sollte die Generierung der persistentID problemlos funktionieren.

Das Beispiel der Uni Jena zeigt, wie bei Bedarf das IdM-Quellattribut gewechselt werden kann, aus dem persistentIDs generiert werden, und wie dabei schon bestehende persistentIds erhalten bleiben.

Ziel der Aktion war das Auswechseln des Quellattributs der persistentId (gespeichert in einer PostgreSQL-Datenbank), die doch nicht so unique uid sollte hierbei durch die eduPersonUniqueId ersetzt werden. Die eduPersonUniqueId bilden wir im IDM aus einer UUID ohne Bindestriche mit Scope hinten dran (Beispiel: 0c845b14f1c643ccac9de204632512cd@uni-xy.de) und stellen sie per LDAP-Server zur Verfügung. Der Shibboleth IdP war Version 3.2.1.

  1. Den IdP stoppen.
  2. In /opt/shibboleth-idp/conf/saml-nameid.properties wird die Eigenschaft idp.persistentId.sourceAttribute = eduPersonUniqueId gesetzt.
  3. Die Werte der Spalte localid in der Tabelle shibpid müssen auf die jeweiligen Werte des Attributs eduPersonUniqueId abgeändert werden. Ich habe mir für die ganze Aktion ein Shellskript geschrieben.
    1. Man erzeugt sich einen Dump der Tabelle shibpid.
    2. Man arbeitet sich zeilenweise durch diesen Dump. Die Spalte principalname in der Tabelle shibpid referenziert den Benutzernamen (uid). Über diesen sucht man nun im LDAP-Server nach der jeweiligen eduPersonUniqueId und setzt in der Spalte localid deren Wert anstelle des bisherigen ein. Beispiel:
      # Aus...
        "https://idp.uni-xy.de/idp/shibboleth";"https://testsp2.aai.dfn.de/shibboleth";"aaidemo";"aaidemo";"Znc0wfn/YabcZe7neb73Es123456";"";"2014-08-12 14:10:47.29";""
      # ...wird so...
        "https://idp.uni-xy.de/idp/shibboleth";"https://testsp2.aai.dfn.de/shibboleth";"aaidemo";"0e2cba36852b44d8be29e4168ec71e0d@uni-xy.de";"Znc0wfn/YabcZe7neb73Es123456";"";"2014-08-12 14:10:47.29";""
    3. Man kopiert den modifizierten Dump zurück in die Tabelle shibpid.
  4. Den IdP wieder starten und überprüfen, ob die Sache funktioniert hat.

Übrig bleibt nun noch das Entfernen der uid als Bestandteil der Bildungsvorschriften anderer Attribute, z.B. beim eduPersonPrincipalName (= uid + „@uni-xy.de“). An den Bestandsnutzern kann man da nichts machen, der Plan ist aber, für neue Benutzer auch hier eduPersonPrincipalName = eduPersonUniqueId auszuliefern. Das sollte dann für eine ausreichende Kollisionsfreiheit sorgen.

  • Zuletzt geändert: vor 5 Monaten