Attr Filter

Reference

EduPersonEntitlement

references

Indications constructions d'attributs

resolver script

exemple de script de provisioning de l'attribut eduPersonEntitlement servant à déterminer l'acces d'un invidu à differentes ressources. ici nous nous basons sur 3 attributs de l'annuaire

  • schacUserStatus
  • email
  • eduPersonPrimaryOrgUnitDN

permettant respectivement de déterminer les droits applicatifs (schacUserStatus ⇒ multivalué, d'où la boucle “for …” dans le script ci-dessous), l'identité personnelle basée sur le mail et l'appartenance à un structure organisationnelle.

/opt/shibboleth-idp/conf/attribute-resolver.xml

<!-- eduPersonEntitlement -->
  <resolver:AttributeDefinition id="eduPersonEntitlement" xsi:type="Script" xmlns="urn:mace:shibboleth:2.0:resolver:ad" >
     <resolver:Dependency ref="ldapTMSP" />
        <resolver:Dependency ref="schacUserStatus" />
       <resolver:Dependency ref="email" />
       <resolver:Dependency ref="eduPersonPrimaryOrgUnitDN" />

       <resolver:AttributeEncoder xsi:type="SAML1String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
           name="urn:mace:dir:attribute-def:eduPersonEntitlement" />
       <resolver:AttributeEncoder xsi:type="SAML2String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
           name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" friendlyName="entitlement" />

    <Script>
     <![CDATA[
       importPackage(Packages.edu.internet2.middleware.shibboleth.common.attribute.provider);
            eduPersonEntitlement = new BasicAttribute("eduPersonEntitlement");


            if (schacUserStatus != null && email != null ) {

                for ( i = 0; schacUserStatus != null && i < schacUserStatus.getValues().size(); i++ ){
                        value = schacUserStatus.getValues().get(i);

                         if (schacUserStatus.getValues().get(i).matches(".*cert.*")) {
                        eduPersonEntitlement.getValues().add("urn:mace:terena.org:tcs:personal-user");
                        }//if
                        else if (schacUserStatus.getValues().get(i).matches(".*conge.*")) {
                                eduPersonEntitlement.getValues().add("urn:mace:it-sudparis.eu:it:personal-conges");
                                }//if
                        else if (schacUserStatus.getValues().get(i).matches(".*wpublic.*")) {
                                eduPersonEntitlement.getValues().add("urn:mace:it-sudparis.eu:it:personal-webspace");
                                }//if
                }

                if (email.getValues().get(0).match("^Prenom1.Nom1@it-sudparis.eu$")) {
                        eduPersonEntitlement.getValues().add("urn:mace:terena.org:tcs:personal-admin");
                }//if
                if (email.getValues().get(0).match("^Prenom2.Nom2@it-sudparis.eu$")) {
                        eduPersonEntitlement.getValues().add("urn:mace:terena.org:tcs:personal-admin");
                }//if

            }//IF

            if (eduPersonPrimaryOrgUnitDN != null ) {
                if (eduPersonPrimaryOrgUnitDN.getValues().get(0).match(".*DISI.*")) {
                        eduPersonEntitlement.getValues().add("urn:mace:it-sudparis.eu:it:struc-dsi-user");
                }//if
            }

        else eduPersonEntitlement.getValues().add("");
     ]]>
   </Script>

 </resolver:AttributeDefinition>

Filter Rules

Les règles de filtrage permettent de définir suivant la ressource accédée (SP), quelles valeurs de l'attribut eduPersonEntitlement nous allons lui fournir.

  <!--       Release eduPersonEntitlement and it's associated permissible values
        to  SP that is a member of FedeIT or Fede Mines    -->
    <AttributeFilterPolicy id="releaseEPeToMinesTelecom">
        <PolicyRequirementRule xsi:type="basic:OR">
            <basic:Rule xsi:type="saml:AttributeRequesterInEntityGroup" groupID="https://federation.institut-telecom.fr/" />
            <basic:Rule xsi:type="saml:AttributeRequesterInEntityGroup" groupID="http://www.mines-nantes.fr/" />
        </PolicyRequirementRule>

        <AttributeRule attributeID="eduPersonEntitlement">
            <PermitValueRule xsi:type="basic:OR">
                <basic:Rule xsi:type="basic:AttributeValueString" value="urn:mace:it-sudparis.eu:it:personal-conges" ignoreCase="true" />
                <basic:Rule xsi:type="basic:AttributeValueString" value="urn:mace:it-sudparis.eu:it:personal-webspace" ignoreCase="true" />
                <basic:Rule xsi:type="basic:AttributeValueString" value="urn:mace:it-sudparis.eu:it:struc-dsi-user" ignoreCase="true" />
            </PermitValueRule>
        </AttributeRule>

    </AttributeFilterPolicy>

      <!--Release eduPersonEntitlement and it's associated permissible values
        to 2 SP; TCS and wpublic  -->

    <AttributeFilterPolicy id="releaseEPeToTCS">
        <PolicyRequirementRule xsi:type="basic:OR">
            <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://tcs-personal-portal.terena.org/simplesamlphp/module.php/saml/sp/metadata.php/default-sp" />
            <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://www-public.it-sudparis.eu" />
        </PolicyRequirementRule>

        <AttributeRule attributeID="eduPersonEntitlement">
            <PermitValueRule xsi:type="basic:OR">
                <basic:Rule xsi:type="basic:AttributeValueString" value="urn:mace:terena.org:tcs:personal-user" ignoreCase="true" />
                <basic:Rule xsi:type="basic:AttributeValueString" value="urn:mace:terena.org:tcs:personal-admin" ignoreCase="true" />
            </PermitValueRule>
        </AttributeRule>

    </AttributeFilterPolicy>

a titre d'exemple ici:

La première règle (AttributeFilterPolicy id=“releaseEPeToMinesTelecom”) envoie aux SP de la fédé Mines-Telecom (groupID) les valeurs de l'attribut eduPersonEntitlement

  • value=“urn:mace:it-sudparis.eu:it:personal-conges”
  • value=“urn:mace:it-sudparis.eu:it:personal-webspace”
  • value=“urn:mace:it-sudparis.eu:it:struc-dsi-user”

Le 2eme (AttributeFilterPolicy id=“releaseEPeToTCS”) envoie au SP TCS de certif personnels et au SP www-public explicitements les valeurs de ce meme attribut les concernants plus spécifiquement:

  • value=“urn:mace:terena.org:tcs:personal-user”
  • value=“urn:mace:terena.org:tcs:personal-admin”

attribut entitlement UPSay

 <!-- eduPersonEntitlement -->
  <resolver:AttributeDefinition id="eduPersonEntitlement" xsi:type="Script" xmlns="urn:mace:shibboleth:2.0:resolver:ad" >
       <resolver:Dependency ref="myLDAP" />
        <resolver:Dependency ref="uid" />
        <resolver:AttributeEncoder xsi:type="SAML1String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
                   name="urn:mace:dir:attribute-def:eduPersonEntitlement" />
                          <resolver:AttributeEncoder xsi:type="SAML2String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
                                     name="urn:oid:1.3.6.1.4.1.5923.1.1.1.7" friendlyName="entitlement" />
<Script>
     <![CDATA[
            importPackage(Packages.edu.internet2.middleware.shibboleth.common.attribute.provider);
                        eduPersonEntitlement = new BasicAttribute("eduPersonEntitlement");
            if (uid != null ) {
                    eduPersonEntitlement.getValues().add("urn:mace:ensta:ups:struc-dsi-user");
                      }//if

                else eduPersonEntitlement.getValues().add("");
             ]]>
                </Script>

 </resolver:AttributeDefinition>

attribute filter

<!-- filtre pour TP UPS -->

   <afp:AttributeFilterPolicy>
        <afp:PolicyRequirementRule xsi:type="basic:OR">
           <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://www-public.it-sudparis.eu/shibboleth" />
           <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://wups.tem-tsp.eu/sp" />
           <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://test.federation.renater.fr/test/ressource" />
     </afp:PolicyRequirementRule>

        <afp:AttributeRule attributeID="email">
            <afp:PermitValueRule xsi:type="basic:ANY" />
        </afp:AttributeRule>

        <afp:AttributeRule attributeID="givenName">
            <afp:PermitValueRule xsi:type="basic:ANY" />
        </afp:AttributeRule>

        <afp:AttributeRule attributeID="eduPersonEntitlement">
            <afp:PermitValueRule xsi:type="basic:ANY" />
        </afp:AttributeRule>

        <afp:AttributeRule attributeID="surname">
            <afp:PermitValueRule xsi:type="basic:ANY" />
        </afp:AttributeRule>
    </afp:AttributeFilterPolicy>

Attribut appartenance IT/DSI

Dans le cadre d'echanges intra communautaires, il peut etre souhaitable de distinguer par exemple les personnels faisant partie d'une DSI (ou autres services) afin de definir des autorisations de lecture et/ou ecriture granulaires par categorie de personnes.

ainsi nous allons prendre l'exemple ci-dessous de contruction d'un attribut maison “depIT” (pour l'exemple) permettant d'aller chercher l'information d'appartenance d'une personne à une DSI dans le referentiel local et de pousser cet attribut dans la reponse de l'IDP au SP , permettant à ce dernier un conrole d'acces fin sur l'appartenance d'un utilisateur une DSI.

Dans cet exemple nous basons la contruction de cet attribut maison sur l'attribut departmentNumber de notre referentiel local où un personnel de la DSI peut contenir plusieurs valeurs dans departmentNumber(DISI, et sous groupes fonctionnels: SRI, SI, SIA), on retournera pour tous la valeur “DSI”. Configuration dans le fichier de l'IDP: attribute-resolver.xml

       <!-- Construction DSI -->

        <resolver:AttributeDefinition xsi:type="Mapped" xmlns="urn:mace:shibboleth:2.0:resolver:ad"
                                     id="depIT"
                                     sourceAttributeID="departmentNumber">
        <resolver:Dependency ref="ldapTMSP" />
       <resolver:AttributeEncoder xsi:type="SAML1String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
                name="urn:mace:dir:attribute-def:depIT" />
       <resolver:AttributeEncoder xsi:type="SAML2String" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
                name="urn:oid:1.3.6.1.4.1.739.4.1.1.2" friendlyName="depIT" />
        <!-- default to the generic value 'affiliate' -->
    <DefaultValue>IT</DefaultValue>
        <!-- map internal values like 'student-worker' and 'undergraduate' to 'student' -->
    <ValueMap>
            <ReturnValue>DSI</ReturnValue>
        <!--<SourceValue ignoreCase="true">CN=.*,ou=permanents,dc=people,dc=mysite,dc=fr</SourceValue> -->
        <SourceValue ignoreCase="true">SIA</SourceValue>
        <SourceValue ignoreCase="true">DISI</SourceValue>
        <SourceValue ignoreCase="true">SRI</SourceValue>
        <SourceValue ignoreCase="true">SI</SourceValue>
    </ValueMap>
    

Controle d'acces Apache

il est possible au niveau du ServiceProvider de filter l'acces a une ressource sur la base d'expressions regulieres .

cf https://spaces.internet2.edu/display/SHIB2/NativeSPhtaccess

exemple:

<Location /wiki>
...
require entitlement ~ ^.+:struc-dsi-user 
</location>

ce qui donnera un acces au cas ou la valeur d'attribut d'EduPersonEntitlement match l'expression régulière, exemple de log du module shib (native.log)

2011-03-09 19:41:00 DEBUG Shibboleth.Apache [16794] shib_auth_checker: htaccess: expecting regexp ^.+:struc-dsi-user, got urn:mace:it-sudparis.eu:it:struc-dsi-user: acccepted
2011-03-09 19:41:00 DEBUG Shibboleth.Apache [16794] shib_auth_checker: htaccess: a rule was successful, granting access 

Exemples d'acces

Ressource fédé mines-telecom

  • SP appartenant au groupID “mines-telecom”

http://infopedia.it-sudparis.eu/test/shib/shibtest.php

entitlement

  • urn:mace:it-sudparis.eu:it:personal-webspace
  • urn:mace:it-sudparis.eu:it:personal-conges
  • urn:mace:it-sudparis.eu:it:struc-dsi-user

* SP appartenant à la fédé “Renater/TCS …”

http://www-public.it-sudparis.eu/test/shib/shibtest.php

entitlement

  • urn:mace:terena.org:tcs:personal-user
  • urn:mace:terena.org:tcs:personal-admin

Debug Log IDP

on vois bien dans le reponse de l'IDP, quand on accede au SP de TCS, qu'il filtre les bonnes valeurs:

$ tail -f  /opt/shibboleth-idp/logs/idp-process.log | grep -i edupersonentitlement

17:39:21.459 - DEBUG [edu.internet2.middleware.shibboleth.common.attribute.resolver.provider.ShibbolethAttributeResolver:316] - Resolved attribute eduPersonEntitlement containing 5 values

17:39:21.477 - DEBUG [edu.internet2.middleware.shibboleth.common.attribute.filtering.provider.ShibbolethAttributeFilteringEngine:156] - Processing permit value rule for attribute eduPersonEntitlement for principal procacci
17:39:21.477 - TRACE [edu.internet2.middleware.shibboleth.common.attribute.filtering.provider.ShibbolethAttributeFilteringEngine:168] - The following value for attribute eduPersonEntitlement does not meet permit value rule: urn:mace:it-sudparis.eu:it:personal-webspace
17:39:21.477 - TRACE [edu.internet2.middleware.shibboleth.common.attribute.filtering.provider.ShibbolethAttributeFilteringEngine:168] - The following value for attribute eduPersonEntitlement does not meet permit value rule: urn:mace:it-sudparis.eu:it:personal-conges
17:39:21.477 - TRACE [edu.internet2.middleware.shibboleth.common.attribute.filtering.provider.ShibbolethAttributeFilteringEngine:168] - The following value for attribute eduPersonEntitlement does not meet permit value rule: urn:mace:it-sudparis.eu:it:struc-dsi-user

Debug Mailing list

PrincipalName pour google

references

Indications Mines-Telecom

Google Metadata

Ajout des metadata google sur notre IdP pour le SP de notre site/domain google (ici tmsp.mines-telecom.fr)

[root@shibidp1 /opt/shibboleth-idp/conf]
$ cat ../metadata/google-metadata.xml
<EntityDescriptor entityID="google.com" xmlns="urn:oasis:names:tc:SAML:2.0:metadata">
    <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">

        <NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat>

        <AssertionConsumerService index="1" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
            Location="https://www.google.com/a/tmsp.mines-telecom.fr/acs" />
    </SPSSODescriptor>
</EntityDescriptor>

RelyingParty google

specification du profile SSO et referencement aux metadata google créé ci-dessus

[root@shibidp1 /opt/shibboleth-idp/conf]
$ vim relying-party.xml

...
   </DefaultRelyingParty>

 <RelyingParty id="google.com"
        provider="https://shibidp1.it-sudparis.eu/idp/shibboleth"
        defaultSigningCredentialRef="IdPCredential">
    <ProfileConfiguration xsi:type="saml:SAML2SSOProfile" encryptAssertions="never" encryptNameIds="never" />
        </RelyingParty>
....
 <!-- Google Metadata -->
        <MetadataProvider id="GoogleMD" xsi:type="FilesystemMetadataProvider" xmlns="urn:mace:shibboleth:2.0:metadata"
         metadataFile="/opt/shibboleth-idp/metadata/google-metadata.xml" maintainExpiredMetadata="true" />


    </MetadataProvider>     

SSO shibboleth

Attention, l'exemple ci-dessus est valable pour un IdP qui authentifie sur la base d'un SSO externe a shibboleth , délégation à CAS via un filtre java en frontal de l'URL /Authn/RemoteUser. Si c'est le SSO shibboleth via le login handler UsernamePassword ; handler.xml :

<!--  Username/password login handler -->
    <LoginHandler xsi:type="UsernamePassword"
                  jaasConfigurationLocation="file:///opt/shibboleth-idp/conf/login.config">
        <AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</AuthenticationMethod>
    </LoginHandler>

il faut alors preciser dans le relying partY concernant google, le defaultAuthenticationMethod a PasswordProtectedTransport ( constat fait sur un site qui n'utilise pas CAS mais le SSO integré a shibboleth ).

<RelyingParty id="google.com"
        provider="https://idp.telecom-paristech.fr/idp/shibboleth"
        defaultSigningCredentialRef="IdPCredential"
        defaultAuthenticationMethod="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport">
    <ProfileConfiguration xsi:type="saml:SAML2SSOProfile" encryptAssertions="never" encryptNameIds="never" />
</RelyingParty>

resolver script

Définition d'un attribut “principal” basé sur le NameId avec un encodage de type SAML2StringNameID pour le SP google. Pour le SP de test https://www-public.it-sudparis.eu, encodage de type SAML1StringNameIdentifier (2eme <resolver:AttributeEncoder …)

<resolver:AttributeDefinition id="principal" xsi:type="PrincipalName" xmlns="urn:mace:shibboleth:2.0:resolver:ad">

    <resolver:AttributeEncoder xsi:type="SAML2StringNameID" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
        nameFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" />
         <resolver:AttributeEncoder xsi:type="SAML1StringNameIdentifier" xmlns="urn:mace:shibboleth:2.0:attribute:encoder"
            nameFormat="urn:mace:shibboleth:1.0:nameIdentifier" />
</resolver:AttributeDefinition>

Filtre

Pour les SP google.com et notre SP de test (https://www-public.it-sudparis.eu) nous permettons toutes valeur (ANY) de l'attribut “principal” . Commenté dans le code ci-dessous, on retrouve un exemple du retrait du transientId ⇒ nameId (opaque) par défaut !.

 <AttributeFilterPolicy id="releasePrincipal">
                <PolicyRequirementRule xsi:type="basic:OR">
                        <basic:Rule xsi:type="basic:AttributeRequesterString" value="google.com" />
                        <basic:Rule xsi:type="basic:AttributeRequesterString" value="https://www-public.it-sudparis.eu" />
                </PolicyRequirementRule>
                <AttributeRule attributeID="principal">
                        <PermitValueRule xsi:type="basic:ANY" />
                </AttributeRule>
        <!--     <AttributeRule attributeID="transientId">
                       <DenyValueRule xsi:type="basic:ANY" />
                </AttributeRule> -->
        </AttributeFilterPolicy>

Decoder sur le SP

Pour tester le resultat coté SP, l'attributeViewer sur http://www-public.it-sudparis.eu/test/shib/shibtest.php permet de visualiser le resultat de notre envoie de “principal” . Pour ce faire ce SP doit creer un attribute-map pour cet attribut.

[root@wpublic /etc/shibboleth]
$ vim attribute-map.xml
...
 <!-- SAML 2.0 and 1 NameID Format: -->
   <Attribute name="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" id="principal">
        <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name"/>
   </Attribute>
   <Attribute name="urn:mace:shibboleth:1.0:nameIdentifier" id="principal">
        <AttributeDecoder xsi:type="NameIDAttributeDecoder" formatter="$Name"/>
   </Attribute>

Debug

Ceci a été réalisé grace a un long thread avec les developpeurs shibboleth: