Attribute Definitions
Section Topics
- OIDC user attributes possible locations
- OIDC Attribute resolving principle, authorization, token and userinfo endpoints
- OIDC attribute encoders
OIDC user attributes possible locations
User attributes may be returned either in ID Token http://openid.net/specs/openid-connect-core-1_0.html#IDToken or in UserInfo response http://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse.
Whether the attribute ends up to the ID Token or UserInfo response depends on authentication request.
- If claim is requested by standard scope parameter, attribute will be set to userinfo response unless response type is "id_token" (i.e. UserInfo endpoint cannot be accessed).
- Client may specifically request claim to be returned either in ID Token or in UserInfo response
Third option is of course some agreement between RP and OP about non standard scope or some out of band agreement.
OIDC Attribute resolving principle, authorization, token and userinfo endpoints.
- Authentication endpoint. Front-channel endpoint responsible of authenticating the user are asking for consent. May return depending on response type ID Token, authorization code or Access Token or any combination of the three items.
- Token endpoint. Back-channel endpoint that is responsible of authenticating the client RP. Swaps authorization code(or Refresh Token) to Access Token, ID Token and to Refresh Token.
Userinfo endpoint. Back-channel endpoint that can be accessed with Access Token returning UserInfo response.
Attribute Resolving principle
Each of the endpoints perform attribute resolving!
Back-channel endpoints do not have all session/context information available!
Attributes that are based on session/context information must be instructed to be carried in tokens (i.e. encoded directly to authorization code and Access Token) unless implicit flow is used.
Attribute resolvers that use session/context information must check the existence for the source information and fail gracefully if checking fails
Resolver example<AttributeDefinition id="password" xsi:type="ScriptedAttribute" dependencyOnly="true" language="nashorn"> <Script><![CDATA[ logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.script.password"); subjectCtx = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectContext"); subject = subjectCtx.getSubjects()[0]; if (!subject.getPrivateCredentials().isEmpty()){ password.addValue(subject.getPrivateCredentials().toArray()[0].getName()); } ]]></Script> </AttributeDefinition>
OIDC attribute encoders
- oidcext:OIDCString, for encoding an IdPAttribute with simple string values as JSON Object.
- oidcext:OIDCScopedString, for encoding an IdPAttribute with scoped string values as JSON Object.
- oidcext:OIDCByte, for encoding an IdPAttribute with binary values as JSON Object.
Encoder formatting options
Default
<AttributeEncoder xsi:type="oidcext:OIDCString" name="affiliation" /> Input: IdPAttribute["member", "staff"] Output: "affiliation": "member staff"
asArray
<AttributeEncoder xsi:type="oidcext:OIDCString" asArray="true" name="affiliation" /> Input: IdPAttribute["member", "staff"] Output: "affiliation":["member","staff"]
asInt
<AttributeEncoder xsi:type="oidcext:OIDCString" asInt="true" name="updated_at" /> Input: IdPAttribute["1536143427"] Output: "updated_at": 1536143427
asBoolean
<AttributeEncoder xsi:type="oidcext:OIDCString" asBoolean="true" name="email_verified" /> Input: IdPAttribute["true"] Output: "email_verified": true
asObject
<AttributeDefinition id="address" xsi:type="ScriptedAttribute"> <Dependency ref="staticAttributes" /> <Script><![CDATA[address.addValue("{\"street_address\":\""+street_address.getValues().get(0) + "\"," +"\"locality\":\""+locality.getValues().get(0) + "\"," +"\"region\":\""+region.getValues().get(0) + "\"," +"\"postal_code\":\""+postal_code.getValues().get(0) + "\"," +"\"country\":\""+country.getValues().get(0) + "\"}");]]></Script> <AttributeEncoder xsi:type="oidcext:OIDCString" asObject="true" name="address" /> </AttributeDefinition> Output: "address":{"street_address":"234 Hollywood Blvd.","country":"US","locality":"Los Angeles","region":"CA","postal_code":"90210"}
Encoder delivery options
placeToIDToken & denyUserinfo
<!-- This demonstrates a claim that is placed always to id token --> <AttributeDefinition id="email_idtoken" xsi:type="Simple" sourceAttributeID="email"> <Dependency ref="email" /> <AttributeEncoder xsi:type="oidcext:OIDCString" placeToIDToken="true" denyUserinfo="true" name="email" /> </AttributeDefinition>
setToToken
Attribute not resolvable in token and UserInfo endpoints must be carried in tokens if necessary.
<AttributeDefinition id="password" xsi:type="ScriptedAttribute" dependencyOnly="true" language="nashorn"> <Script><![CDATA[ logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.script.password"); subjectCtx = profileContext.getSubcontext("net.shibboleth.idp.authn.context.SubjectContext"); <!-- Subject does not have credentials populated in Token and UserInfo endpoints, have to give up in such case --> if (subjectCtx!=null){ subject = subjectCtx.getSubjects()[0]; password.addValue(subject.getPrivateCredentials().toArray()[0].getName()); } ]]></Script> <AttributeEncoder xsi:type="oidcext:OIDCString" setToToken="true" name="password"/> </AttributeDefinition>
Exercises
Available contexts in Endpoints
Add the following attribute definition to attribute-resolver.xml. Resolver changes require restarting Shibboleth IdP
nano /opt/shibboleth-idp/conf/attribute-resolver.xml <AttributeDefinition id="scriptedAuthenticationFlowId" xsi:type="ScriptedAttribute" language="nashorn"> <Script><![CDATA[ logger = Java.type("org.slf4j.LoggerFactory").getLogger("net.shibboleth.idp.script.password"); authnCtx = profileContext.getSubcontext("net.shibboleth.idp.authn.context.AuthenticationContext"); scriptedAuthenticationFlowId.addValue(authnCtx.getAuthenticationResult().getAuthenticationFlowId()); ]]></Script> <AttributeEncoder xsi:type="oidcext:OIDCString" setToToken="true" name="flow_id"/> </AttributeDefinition>
Authenticate user using with this new configuration. We are not creating release rules for the attribute, yet. See log for any errors related to the attribute.
Change the response type to "id_token". It means we are using only authentication endpoint.
nano +636 /etc/httpd/conf.d/auth_openidc.conf OIDCResponseType "id_token" service httpd restart
Authenticate user using with this new configuration. Notice there are not errors related to resolving the attribute. Can you explain why?
Change the response type back to "code". Correct the attribute to not cause errors. Correct also the attribute to be carried in tokens.
Formatting attribute
Create a new attribute attribute called "manipe" with static values "zero", "1", "3" and "two".
Update the filtering rules to release it all RPs asking for profile scope.
Authenticate the user. Locate "manipe" claim from the UserInfo response.
Instruct "manipe" to be encoded as an array. Verify the result from the UserInfo response.
Instruct "manipe" to be encoded as an array of integers. Verify the result from the UserInfo response.