Attribute Filtering

Section Topics

  • Requesting Attributes in OIDC
  • Filtering attributes for OIDC RPs

Requesting Attributes in OIDC

There are two main mechanisms for RP to ask for attributes,

  • Authentication request scope - parameter
    • There is a set of standard scope values profile, email, address and phone.
    • The claims requested by the standard scope values are expected to be returned from UserInfo endpoint unless response type is "id_token"
    • The claims requested by the standard scope values are treated as voluntary
    • You may define your own scope values and rules for them. This has to be agreed by both parties of course. 
  • Authentication request claims - parameter
    • You must declare the target for the claim, ID Token or UserInfo response
    • You may list the claim as essential claim
    • You may list a expected value for the claim

Claims Request
{
   "userinfo":
    {
     "given_name": {"essential": true},
     "nickname": null,
     "picture": null,
     "http://example.info/claims/groups": null
    },
   "id_token":
    {
     "email": {"essential": true},
     "email_verified": {"essential": true},
     "sub": {"value": "248289761001"}
     "auth_time": {"essential": true},
     "acr": {"essential": true,
             "values": ["urn:mace:incommon:iap:silver",
                        "urn:mace:incommon:iap:bronze"]}
    }
  }


Filtering attributes for OIDC RPs

It is your job to resolve and filter attributes to match the requests. OIDC extension has reserved the right to control some claims you should not try to resolve or filter. 

oidcext:OIDCScope

PolicyRule which returns true if any of the scope values in the authentication request matches a supplied string.

OIDCScope
 <!-- This demonstrates a rule that releases email claims in response to all oidc authentication requests having scope
        email. The requester needs to have scope email as a registered scope. -->

<AttributeFilterPolicy id="OPENID_SCOPE_EMAIL">
    <PolicyRequirementRule xsi:type="oidcext:OIDCScope" value="email" />
    <AttributeRule attributeID="email">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
    <AttributeRule attributeID="email_verified">
        <PermitValueRule xsi:type="ANY" />
    </AttributeRule>
</AttributeFilterPolicy>

oidcext:AttributeInOIDCRequestedClaims

Matcher which returns attribute values after comparing them to requested claims parameter of oidc authentication request.

AttributeInOIDCRequestedClaims
 <!-- This demonstrates a rule that releases email in id token if specifically asked to be released as essential for id token -->

<AttributeFilterPolicy id="REQUESTED_CLAIMS">
    <PolicyRequirementRule xsi:type="ANY" />
    <AttributeRule attributeID="email_idtoken">
        <PermitValueRule xsi:type="oidcext:AttributeInOIDCRequestedClaims" matchOnlyIDToken="true" onlyIfEssential="true" />
    </AttributeRule>
</AttributeFilterPolicy>

Exercises

Exercise 5.1

Define a new scope "campus". Target is to have scope "campus" that includes a claim "campus_id" to ID Token.

  1. Add "campusId" attribute definition to attribute resolver and add a value for it in staticAttributes data connector. Add a new filtering rules that releases campusId when scope "campus" is requested.

    Hints, Tips and Result
    nano /opt/shibboleth-idp/conf/attribute-resolver.xml
    
    <AttributeDefinition id="campusId" xsi:type="Simple" sourceAttributeID="campusId">
        <Dependency ref="staticAttributes" />
        <AttributeEncoder xsi:type="oidcext:OIDCString" name="campus_id" />
    </AttributeDefinition>
    
    
    <Attribute id="campusId">
        <Value>New Campus</Value>
    </Attribute>
    
    
    nano /opt/shibboleth-idp/conf/attribute-filter.xml
    
    <AttributeFilterPolicy id="OPENID_SCOPE_CAMPUS">
        <PolicyRequirementRule xsi:type="oidcext:OIDCScope" value="campus" />
        <AttributeRule attributeID="campusId">
            <PermitValueRule xsi:type="ANY" />
        </AttributeRule>
    </AttributeFilterPolicy>
  2. Modify client RP to request for scope "campus".

    nano +643 /etc/httpd/conf.d/auth_openidc.conf
    
    OIDCScope "openid campus"
    
    service httpd restart
  3. Authenticate the user. Verify from the logs that scope "campus" is being requested. Find out from the logs why it is not being released.

    Hints, Tips and Result
    [root@gn43-oidcshibop-devel conf]# grep campus  /opt/shibboleth-idp/logs/idp-process.log 
    2018-09-24 05:27:27,048 - INFO [net.shibboleth.idp.attribute.resolver.spring.BaseResolverPluginParser:63] - Parsing configuration for AttributeDefinition plugin with id: campusId
        scope:openid campus
    2018-09-24 05:40:41,506 - DEBUG [org.geant.idpextension.oidc.decoding.impl.OIDCAuthenticationRequestDecoder:69] - Decoded inbound request query string login_hint=teppo%40192.168.0.150&scope=openid+campus&claims=%7B%22id_token%22%3A%7B%22acr%22%3A%7B%22values%22%3A%5B%22urn%3Amace%3Aincommon%3Aiap%3Asilver%22%2C%22urn%3Amace%3Aincommon%3Aiap%3Abronze%22%5D%2C%22essential%22%3Atrue%7D%7D%7D&response_type=code&redirect_uri=https%3A%2F%2F192.168.0.150%3A8443%2Fprotected%2Fredirect_uri&state=GfF7nJQf2lEQZIvFOj9UZMCxLYY&nonce=7XWKLlplp2TNt5gHCHS4QGg9XgglPzXGSMNcXyRT1IM&client_id=_6abd8ce1be06caf6c65b79934dfd5a01
    2018-09-24 05:40:41,768 - WARN [org.geant.idpextension.oidc.profile.impl.ValidateScope:93] - Profile Action ValidateScope: removing requested scope campus for rp _6abd8ce1be06caf6c65b79934dfd5a01 as it is not a registered one
  4. Add scope "campus" for the RP as a valid scope value.
  5. Authenticate the user. Verify from the logs that scope "campus" is being requested. Find out from the logs is it being released to ID Token or to UserInfo response.

    Hints, Tips and Result
    grep id_token /opt/shibboleth-idp/logs/idp-process.log 
    
    Content:{"access_token":"AAdzZWNyZXQx6kaWFa5m2rBYllmrWmypRG6o8acq7EsttE-kkEqpF_llEOeZ-RWze1B-p18f3rVWUH4dC_DQP8OHkoYbJuCBHpKdEOSNsmjCvO7MElb_p5VeiiyUqtVAcYnjWe0CAUF0w_lGHKndleYiWjzO_EhGuvH-zwui-HgvS65A3VNUYtfbUt6fxm-yC8KoVBfN7TjWhIu6wV_lhUFZuNWpI4HMhwLhV4vqcpAyVwqPmUJzcDqOT2ltktMGImeZmDl3a_rAvfZhF2VZc6K9xdEcu6NEMbasbQgCutWJkvrTfkBgMspdGn2_YYapxOWImkMS4s0fYEEdcwMB8nxQRKMpP_JmiV5hIMMFiZSg4qa5J9N2t5oI_F-vO2nG5Q7bBMyPmvLCcBcXPOVbP2fqZyu_hCcxBwYjnwURYlp1jN-V9dtG_vdRa5Ddn3P0QcrJQDTQDrAsnkn51NB24b56CiQjj4kVFrc4qNpeDhQ7dgG3M19BKD1rdoFMaNTStN0_Br3YD2G0B4GDJX3I6UJOM4ksmbqDb5aknDgSMxnJHDt96LQqoNmDNI-RugE3Ombit9ZAUaRuAXMAKvR6gXK5gfhr8LzqflF8k2DTVLPyvI1q","refresh_token":"AAdzZWNyZXQxvJQv2UDhK1QGie4smtxaYDD9uwFMk09syFcROFj851zrNb1a7UXBSmp6VYJjYHsXyyIBe0-BQ4_vA7WL-Yuc1u-rJ951w3uKytERn87s0ZGTv45mCVpvlisLpL_XAu6x6Jh7DpOCP7b1FZYH2ctWIYx-Vo9QLya1b1Zys3fohU6Rg5O24ZvtTuUJugFPyDOdaCjO5tTP2eSVSEGrm8-NFz_z0VLWdqwCCjhPKq3FKSXmDo6UX1wyxLtH0DVLoBrAJrZtHMrjsNI1jJQY6IeNl_yxN6Hl_0FNmhmbEgD8zMT0N9-zlrno4w7NPHBQK5ytFCXixmXEK9xgjlf3uqoLQMVMuTuMvee6hQNgRzawcYU3R5jN9KtCNN_NR0v5n8-R3QTlHlYn7Agdhm1UpEuKomXFCy9fo9Psq2haOj588Yt0YaHqp877bofP5SjaNVSixC7TECwAjc11yg2JhRSPGUHQwlRzFuVhUdpVgdNZfSD70nrdAMUv_--XVEdzg9vnCNjPk7XE3jjVijvugaVZvUV2HO6RnhQRWCg12lfOROmBq0bUlaMPaC87zwBlEI9GjQOG_e1fw-K3BfcC7WdQ9DVEtPuOrRh0qA0","id_token":"eyJraWQiOiJ0ZXN0a2V5UlMiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoib1RBc3dNX2pxR0pncHo4WDkzRWNydyIsInN1YiI6IlZVRzQ3NzdZUDNOTVU1S1JGRVNYNlNLUkFQWExFNE1JIiwiYXVkIjoiX2ZhYmJjNmY5MGExMmZmYjNmZWUwMDEwZDRjMmFiZGVlIiwiYWNyIjoidXJuOm1hY2U6aW5jb21tb246aWFwOnNpbHZlciIsImF1dGhfdGltZSI6MTUzNzc3Mjc4NiwiaXNzIjoiaHR0cHM6XC9cLzE5Mi4xNjguMC4xNTAiLCJleHAiOjE1Mzc3NzYzODcsImlhdCI6MTUzNzc3Mjc4Nywibm9uY2UiOiJ3NnJzdkh2d05UX0FuSVZ3OFh1UTlucG5iLXFBZ18yenEySTdtUEJMNkdNIn0.Iqraic8ugywq2_saSoIGIBCZFJIArgUiVvnRQxyjemmZdUG7hxU7lJ06GogBGNmnKDwhOqiA-Ck1SB2iVkvA1YbK3xGgCBO4kkYQSWGjQ1Mq1R-3J0_OPZ5SU5pjcpo4YUBGqYpOjv2WDAftfpBgGr0HmXRjTd_CLxcm8AM5XMwokCJufqoP7l6fjAhxcKweQNPnGEASCG200wTNHIEA82wvOHxZ9BrjB65kyM2lODL40T9NJ5UVvAGHzMzrcw2PUHrhnBGKLmGe89oSO0ww3KfxDiU7vg2jg36xnoMUVwN8RFad7-fNzH3JwNEMzekQBuusDxrxAHlaVHntTZndrw","token_type":"Bearer","expires_in":600}
    
    Decode id token, you will get something like:
    
    {
     kid: "testkeyRS",
     alg: "RS256"
    }.{
     at_hash: "oTAswM_jqGJgpz8X93Ecrw",
     sub: "VUG4777YP3NMU5KRFESX6SKRAPXLE4MI",
     aud: "_fabbc6f90a12ffb3fee0010d4c2abdee",
     acr: "password",
     auth_time: 1537772786,
     iss: "https:\/\/192.168.0.150",
     exp: 1537776387,
     iat: 1537772787,
     nonce: "w6rsvHvwNT_AnIVw8XuQ9npnb-qAg_2zq2I7mPBL6GM"
    }.[signature]
    
    Check now userinfo response. It is one of the last lines in the log now
    
    tail /opt/shibboleth-idp/logs/idp-process.log
     
    Content:{"sub":"VUG4777YP3NMU5KRFESX6SKRAPXLE4MI","campus_id":"Y2FtcHVzSWQ="}
    
    You notice the campus_id is only in the userinfo response.
  6. Modify "campusId" attribute resolver to encode the claim always and only to ID Token.

    Hints, Tips and Result
    <AttributeDefinition id="campusId" xsi:type="Simple" sourceAttributeID="campusId">
        <Dependency ref="staticAttributes" />
        <AttributeEncoder xsi:type="oidcext:OIDCString" name="campus_id" placeToIDToken="true" denyUserinfo="true"/>
    </AttributeDefinition>
  7. Authenticate the user. Verify from the logs that scope "campus" is being requested. Verify  from the logs it is being released only to ID Token.

    Hints, Tips and Result
    grep id_token /opt/shibboleth-idp/logs/idp-process.log 
    
    Content:{"access_token":"AAdzZWNyZXQxX6FZjPLkXdPUi2UBqUNnkcNwayEbDbrsL_LHumwkbTpLM2W8QVEOGhHRsh-sAtKeaIFx1568_AAESKeHT7qFSJYKOavGxj17wVBJ_S8mQGW7YcIIfL2hAC-LnHtvCgY8n_r-WsD_HVJN3UqQ0GijbPeX4NHEENfBgG18oEO1bbSMHR0XhBCY0sLcubfaXl7N0E17COObm992Su5jFsvZptfgmYWgkV3OYzX4684bNL2F_8-6w1TblGpNgXIi0ORci7FSXP0oMQfxb_AeAfADe3n-tl_4dUeJ-rrKP-oG-rUsnkEQQqHUgtBZEIV-YmIYhA3UP1Ux35XpFYwrbMYSb7yZ2zeH-fiukZGiStMxoifVmldzeKTZ8euO69lcZqv1WZGWueMmZ3ltfCWH3V5XI26KjYJgnxaX9FGVG4wRBm_yCclgtuplscs8Ixvmrr4HyaSQZOGOS0d8Ri4q6KnKqaob4zCAX2GGkBCWCtYQpTKfotLWWwvNorxhPlyVoorOLDKe2eTl3en4H9RGl_xvaYZTIMyu0bB-eUJgeXyskz_TEjDpnnBoSSBSO2daBNZPnsQUaLnz5E0RK_C7it73hc2TWrNXWkA7pA","refresh_token":"AAdzZWNyZXQxjINhPCFGNntDfeWtxJhGEToRHe3CwPT3WTQJO-7GQBmNHSGiK3dzGPILulNKHI8Akhf7CZiYePeB5AEyV2mFvF5142QjmG0hao_pyH08WyCI9m9XSrGR7QxhzYPdKgShAAoJUyLkNBjswV2B0HsW2dg6tys4WZW7bMPOSmJ_o6mIFuuG6umzWUJkKSyqDcuvfUBQdNKZ73UHYMDheuTeZ8VrF9-6CcUsBkG7EEEwIogpJ4tXGUcstZ-3lKeEf3RR68Ag7Okoy7G-QqBL28KtCOKTery5iqB5ZbKGqxoGDfHEe1c5TqVbRp7pvvISTMVx8EgDuFoUnUC0IGAoFoFMf4WH0fCwN4kQL2WRfsYiyoHliC0aw2nfI2gV-rciO9K26kj6mmxBf71urV2HKmjdJg8cR-V3m5T80D94e14jJFewyFs1_3XYgbkDu5CeeptesgObLBYy0oYCLEqxt4ht_-fxNqBmsrnganoIn4tYRzXDyTkUXJv8w-foFfkiC484crWlutAEbXzAKipDn2t43k9HOHFdM3nofw4CnY4YHeRMsOphIFEHXSYOgBa73zr4dzdR5If9ivLcuuRNe7lfmaEEhwzcqllG-FDU9s0GQA","id_token":"eyJraWQiOiJ0ZXN0a2V5UlMiLCJhbGciOiJSUzI1NiJ9.eyJhdF9oYXNoIjoiWjlPNjRkYVFUbXhKeE9obmZtdkl2USIsInN1YiI6IlZVRzQ3NzdZUDNOTVU1S1JGRVNYNlNLUkFQWExFNE1JIiwiYXVkIjoiX2ZhYmJjNmY5MGExMmZmYjNmZWUwMDEwZDRjMmFiZGVlIiwiYWNyIjoidXJuOm1hY2U6aW5jb21tb246aWFwOnNpbHZlciIsImF1dGhfdGltZSI6MTUzNzc3MzIyMCwiaXNzIjoiaHR0cHM6XC9cLzE5Mi4xNjguMC4xNTAiLCJleHAiOjE1Mzc3NzY4MjQsImlhdCI6MTUzNzc3MzIyNCwibm9uY2UiOiJfcDdCX3lWeDlsQUhEelJQcGhnWkNRa2JYdmNnMC1UR0JqTm9ONVZvdTlrIiwiY2FtcHVzX2lkIjoiWTJGdGNIVnpTV1E9In0.ejxpf9N3LW4UqMlbB92F2_DUSNyVwHUckCPYNGO11WxkGRFd9mOKDC1m217f6ezQmZceyTT7rckkmWhWGDDQeJoxKJGzji0tmSHzZU62FAm32zxRL49rlmRT-cBpfH7cpAMjmhi8ORjci8pER7M205IL2ANXzM_q8RnLgtS9r4ztm9Xpmu83bPea-y4Qqm1phpsejPbIanDNZ7WmrChD26_lrSid8dOLu_VTta3Mgh_BcF0sQbnvxSpz5VQIJBHp7vlfxuipfHPMrc96Pqj_6pksQHQjvBOGr9yLIXF6lO6ja7-8dTRMlOhvTae2tbec62ptepLK5_OSgOFT_GwhEQ","token_type":"Bearer","expires_in":600}
    
    Decode id token, you will get something like:
    
    {
     kid: "testkeyRS",
     alg: "RS256"
    }.{
     at_hash: "Z9O64daQTmxJxOhnfmvIvQ",
     sub: "VUG4777YP3NMU5KRFESX6SKRAPXLE4MI",
     aud: "_fabbc6f90a12ffb3fee0010d4c2abdee",
     acr: "password",
     auth_time: 1537773220,
     iss: "https:\/\/192.168.0.150",
     exp: 1537776824,
     iat: 1537773224,
     nonce: "_p7B_yVx9lAHDzRPphgZCQkbXvcg0-TGBjNoN5Vou9k",
     campus_id: "Y2FtcHVzSWQ="
    }.[signature]
    
    Check now userinfo response. It is one of the last lines in the log now
    
    tail /opt/shibboleth-idp/logs/idp-process.log
     
    Content:{"sub":"VUG4777YP3NMU5KRFESX6SKRAPXLE4MI"}
    
    You notice the campus_id is only in the id token.
Exercise 5.2

Define attribute release rules to release "campusId" attribute to be released if asked to be released for ID Token as essential claim.

    1. Make sure "campusId" is not requested anymore by scope.

nano +643 /etc/httpd/conf.d/auth_openidc.conf

OIDCScope "openid"

    2. Modify RP to ask "campusId" as essential ID Token claim.

nano +417 /etc/httpd/conf.d/auth_openidc.conf

OIDCAuthRequestParams claims=%7B%22id_token%22%3A%7B%22campus_id%22%3A+%7B%22essential%22%3A+true%7D%7D%7D

service httpd restart

   3. Add a new filtering rule that will release "campusId" only if requested to be released as essential ID Token claim


Hints, Tips and Result
<AttributeFilterPolicy id="REQUESTED_CAMPUS_CLAIMS">
    <PolicyRequirementRule xsi:type="ANY" />
    <AttributeRule attributeID="campusId">
        <PermitValueRule xsi:type="oidcext:AttributeInOIDCRequestedClaims" matchOnlyIDToken="true" onlyIfEssential="true" />
    </AttributeRule>
</AttributeFilterPolicy>

4. Authenticate the user and verify from the logs the attribute is released. At this point you should be able to do it without hints and tips.


  • No labels