Background
JSON Web Tokens are used prolifically in today's enterprise identity and access management systems. They are JavaScript friendly and are part of a well defined specification to promote secure single sign on capabilities.
The IBM Security Access Manager (ISAM) for Advanced Access Control (AAC) Module supports compliant OIDC flows such as Authorization Code, Implicit, and hybrid flows. It leverages use of the ISAM for Web Reverse Proxy credential to act as the OIDC OpenID Provider (OP) which can be enriched using an External Authentication Interface or with attributes from the underlying LDAP Registry.
There are a few ways to achieve this result.
A) Using Attribute Sources to define 'scope' related attributes
The following video will demonstrate how to :
- Define a server connection to an external ldap
- Define a credential attribute source to retrieve the ISAM groups
- Define an LDAP attribute source to retrieve a multi-valued attribute from the intended server
- Add those attributes to an API Protection Definition
The following video will demonstrate a sample Authorization Code OIDC flow that results in the desired attributes being inserted into the ID Token
B) Using mapping rules to define 'scope' related attributes
I also wanted to highlight a few mapping rule functions I created to handle multi-valued attributes and insert them into the resulting OIDC ID Token when your site is being used as an OIDC OP.
For my example I used the Access Manager Credential Groups, which are stored in a credential attribute called 'AZN_CRED_GROUPS'.
A high level overview of the process is :
- Identify the multi-valued attribute to be stored
- Marshall the values into separate attributes that can be stored for use at the '/token' endpoint
- Retrieve and process the desired attributes
The following are examples of how to achieve this in two common OIDC flows.
a) Authorization Code OIDC flow
The following example code can be inserted on line 795 of the 'PreTokenGeneration' mapping rule for your desired OpenID Connect Provider definition:
// Added to support multi-valued attributes
var multivaluedAttrs = "";
storeMultiValuedAttribute("AZN_CRED_GROUPS","groups",multivaluedAttrs);
if(multivaluedAttrs != null && multivaluedAttrs != ""){
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("multivaluedAttributes","urn:ibm:names:ITFIM:oidc:claim:value",multivaluedAttrs));
}
// End add to support multi-valued attributes
The following can be inserted after line 812 of the 'PreTokenGeneration' mapping rule for your desired OpenID Connect Provider definition after adding the above:
processMultiValuedAttributes();
Update the 'storeMultiValuedAttribute' with your desired values.
You'll need to add the following two functions at the end of your PreTokenGeneration mapping rule:
storeMultiValuedAttribute.js
processMultiValuedAttributes.js
They can be safely inserted at the end of your mapping rule for use in an Authorization Code Flow scenario.
b) Implicit OIDC flow
The following can be inserted onto line 833 of the default PreTokenGeneration mapping rule:
processAndStoreMultiValueAttrs("AZN_CRED_GROUPS","groups");
You'll need to add the following function at the end of your PreTokenGeneration mapping rule:
processAndStoreMultiValueAttrs.js
They can be safely inserted at the end of your mapping rule for use in an Implicit Code scenario.
Updates since initial publication:
After the initial publication of this blog I realized that my functions did not handle two separate scenarios.
The first scenario is that the attribute was not included in the ID Token when there was a 'scope' value that matched the name of the outgoing attribute. This was working as designed as the included scopes become attributes in the outgoing STSUU whenever specified. To fix this I've added a boolean attribute to the process function that allows you to overwrite the value of the existing attribute created by the AAC OIDC module.
The second scenario was that the attributes would always show up in the OIDC token regardless of what scope was passed. This is incorrect as having no scopes should not result in extra attributes being sent. To rectify this I've added logic to the storage function to determine how to treat scopes.
A) A value of 'true' will only insert the attributes into the ID Token if a scope with the same name as the outgoingAttributeName value is present
B) A value of 'false' will not perform any scope checking and will insert the attribute into the ID Token.