OAuth and OIDC mapping rules actions
We can modify mapping rules to perform actions needed for an OAuth or OIDC deployment. Note that for certain grant types, some actions must be performed in the pre-token mapping rule. For instructions on replacing a mapping rule after you make the updates to the file, see Manage OAuth 2.0 and OIDC mapping rules.
Resource owner password credentials (ROPC) grant type flow
For the ROPC flow, the pre-token mapping rule is responsible for performing validation of the user name and password. This validation can be performed in various ways. The pre-defined rule that is included with the appliance provides the following examples:
- Use UserLookupHelper to validate a user name and password against a configured LDAP. We can also use the java class PluginUtils but it is limited. To configure the LDAP to be used, see Configure username and password authentication.
- Validate the user name and password through an HTTP callout. The mapping rule sends the user name and password to a web service. As the format of the messages is not fixed, various services (for example, REST, SOAP, SCIM) can be used for this purpose. Javadoc on the HTTP client and all other exposed Java classes available in mapping rules can be downloaded from the appliance File Downloads page under the path access_control > doc > ISAM-javadoc.zip.
JWT and SAML bearer grant type flow
For the JWT or SAML assertion bearer grant type flows, the pre-token mapping rule must perform the following actions:
- Validate the assertion, including but not limited to:
- Validate the signature (if signed).
- Decrypt the assertion (if encrypted).
- Check the expiry and "not before" value of the assertion.
- Ensure the issuer is a trusted party.
- Extract the subject from the assertion and set the USERNAME field of the STSUU.
The USERNAME field of the STSUU can be set via a call, for example:
// username is a variable containing the subject of the assertion
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("username","urn:ibm:names:ITFIM:oauth:rule:decision", username));The validation of the assertion can be performed in various ways:
- HTTP callout to a web service. Use the HTTP client to perform this.
- WS-Trust request to the Secure Token Service (STS).
- A chain must be configured to consume the assertion and return the required information.
- The STSClientHelper will be called to invoke the STS via HTTP. For more information about this class, see the Javadoc that is embedded in the appliance.
Any attributes of the assertion can be extracted and associated to the OAuth grant to be used later. For information about associating attributes, see OAuth 2.0 and OIDC mapping rule methods.
- The type of the username attribute added must be "urn:ibm:names:ITFIM:oauth:rule:decision" to ensure that only a value populated from the rule is used.
OAuth 2.0 token limits
We can define limits on the number of OAuth tokens per user per definition so the high-volume database does not go beyond capacity.Security Verify Access for Mobile has a thread that runs at a specified interval defined by the advanced configuration property, oauth20.tokenCache.cleanupWait. This property defines the amount of time, in seconds, to wait before it performs another cleanup of expired grants and tokens in the OAuth 2.0 token cache.
Depending on the interval and use of OAuth grants and tokens, there is a possibility the capacity of the high-volume database can be reached before the cleanup process runs. If this happens, the appliance can be negatively impacted.
To prevent issues such as this, the OAuth PreTokenGeneration mapping rule, by default, limits the number of OAuth tokens per user per client definition. When a user requests an OAuth token, the current number of tokens for that user and the specified client definition will be compared to the maximum allowed. If the maximum is exceeded, an error message is returned to the user.
An additional algorithm implements least recently used (LRU) and, if the maximum is exceeded, the least recently used token determined by the date last used for that user and client definition will be removed from the high-volume database.
We can set the limit and algorithm to use, which are controlled by variables in the mapping rule file. Two algorithms are implemented in this mapping rule:
- Strictly enforce the limit.
- When the limit is reached, remove the least recently used tokens for the user per client.
Update the OAuth PreTokenGeneration mapping rule, oauth_20_pre_mapping.js to modify the algorithms. See the comments in the code for an explanation of the values we can modify.
See Updating PreTokenGeneration to limit OAuth tokens so that any API protection definitions you created in versions prior to 8.0.1.2 can take advantage of these limits.
Customize OAuth tokens by updating the sample PreTokenGeneration mapping rule
We can customize the format of the tokens that are issued by your OAuth definition.The OAuth tokens can be customized by modifying the sample PreTokenGeneration mapping rule. Enable the PreTokenGeneration mapping rule on the appliance by setting the variable enable_custom_tokens to true. When custom token formats are used, the tokens must remain unique. Otherwise, users might become authenticated with another user's credential. Thus, IBM recommends that custom tokens always contain a nonce of reasonable entropy. To customize the authorization code, insert a context attribute into the STSUU with the type "urn:ibm:ITFIM:oauth20:custom:token" and the name...
"urn:ibm:ITFIM:oauth20:custom:token:authorization_code"
The provided value will be used as the authorization code if an authorization code would have been issued in this request. To customize the access token, insert a context attribute into the STSUU with the type...
"urn:ibm:ITFIM:oauth20:custom:token"
...and the name...
"urn:ibm:ITFIM:oauth20:custom:token:access_token"
The provided value will be used as the access token if an access token would have been issued as part of this request. To customize the refresh token, insert a context attribute into the STSUU with the type...
"urn:ibm:ITFIM:oauth20:custom:token"
...and the name...
"urn:ibm:ITFIM:oauth20:custom:token:refresh_token"
The provided value will be used as the refresh token if a refresh token would have been issued as part of this request.
Returning additional attributes in responses
To return additional attributes to an OAuth response, modify the pre or post token mapping rule to add an attribute with the name and value of the desired response attribute, and specify the well-known type urn:ibm:names:ITFIM:oauth:response:attribute. We can also use the post token mapping rule to modify any response attributes which are already included.
Here is an example of adding a new response attribute in JavaScript.
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("myAdditionalAttribute" ,"urn:ibm:names:ITFIM:oauth:response:attribute", "myValue"));
To return a multi-valued attribute, provide a Java array as the value. Here is an example of constructing and returning a multi-valued response attribute.
var javaArray = java.lang.reflect.Array.newInstance(java.lang.String, 1);
javaArray[0] = 'myValue';
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("myAdditionalAttribute" ,"urn:ibm:names:ITFIM:oauth:response:attribute", javaArray));Here is an example of an access_token response using the same examples:
{ "access_token": "afcddfegeedffdeeabb", "refresh_token": "cbbdegfcgcffgffdcbdeafadaccegaebeebeaagd", "scope": "scope1", "myAdditionalAttribute": "myValue", "token_type": "bearer", "expires_in": 3589 }{ "access_token": "gdbafbcgffcggfgeccb", "refresh_token": "dfgagecdgbeddeebbedcdacegdacccccfafabcee", "scope": "scope1", "myAdditionalAttribute": [ "myValue", "mySecondValue" ], "token_type": "bearer", "expires_in": 3589 }This action is commonly performed for the response types:
- authorize
- access_token
- introspect
- userinfo
- revoke
When used for revoke, JSON will be returned rather than a 200 with no body.
Customize ID Tokens
For OIDC deployments, the post-mapping rule oauth_20_pre_mapping.js provides examples for how to customize ID tokens. When populating an ID token, the rule processes essential claims and voluntary claims separately so they are treated appropriately if they have no value. In the STSUU, the attribute's name is the claim name and the attribute's value(s) are the expected value of the claim. See the mapping rule for more information.Customize UserInfo
For OIDC deployments, the post-mapping rule oauth_20_post_mapping.js provides examples for how to customize Userinfo based on OIDC scope and claims request parameters. In the STSUU context, the claims are listed in terms of essential and voluntary claims. When AttributeSources are configured in the definition, they too are resolved and available in the STSUU. This is one way of doing customization.Produce JWT Userinfo
For OIDC deployments, the post-mapping rule oauth_20_post_mapping.js provides examples for how to produce JWT UserInfo. In the STSUU context, the signing and encryption data (based on the OP Definition) are available. To create JWT, we can call an STS Chain which has 2 modules: 1) Default STSUU validation module, 2) Default JWT issuer module. We must create this chain, it is not supplied by default. The chain passes the signature and encryption data and all the JWT claims. The JWT token result then needs to be set back in the STSUU under specific name and type. See the mapping rule file for more information.Modify JWT signing and encryption parameters in the pre-token mapping rule
This action applies only when OIDC is enabled.
When using OIDC, the JSON Web Token (JWT) configuration is sourced from the OAuth definition. However, an administrator may want to write logic which at runtime augments how a JWT is formed. For example, specifying a different certificate when signing JWTs for a specific client or specific type of client. We can take this action within the pre-token mapping rule for the definition. The JWT STS module is used to build the JWT that is returned in the OIDC flow. This module allows a well-known set of claims to be provided at runtime. For documentation on those values, see Issue mode.
When making use of the issue context attributes defined in the JWT STS module, the values must be provided using a different and specific attribute type. When calling the STS, the STS Universal User (STSUU) provided is just for a JWT. For OIDC, the STSUU is an encapsulation of the HTTP request. To provide a custom property for building a JWT, set a context attribute with the name and attribute as described in the "Issue mode" link, but use the attribute type urn:ibm:oidc10:jwt:create. To set a JWT claim or header claim (not how the actual JWT is formed), use the types urn:ibm:jwt:claim or urn:ibm:JWT:header:claim, respectively. The Security Token Service Universal User (STSUU) document is an XML representation of a request that passes through a trust module chain in the STS. The three elements in the STS Universal User document are Principal, AttributeList, and RequestSecurityToken. For information on the role of the STSUU in identity mapping, see Security Token Service Universal User document. The following example ensures the JWT that is issued uses HS256 signing with the provided key. This action overrides the configuration in the OAuth definition.
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("signing.alg", "urn:ibm:oidc10:jwt:create", "HS256"));
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("signing.symmetricKey", "urn:ibm:oidc10:jwt:create", "myKey"));The following code adds an extra header to the JWT (in this case, the cty field).
stsuu.addContextAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("cty","urn:ibm:JWT:header:claim", "JWT"));
The following code adds a static claim to the JWT claims.
stsuu.addAttribute(new com.tivoli.am.fim.trustserver.sts.uuser.Attribute("myClaim", "urn:ibm:jwt:claim", "claimValue"));
Here is a raw JWT produced with all 4 of the above examples enabled.
eyJjdHkiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJub25jZSI6InNvbWVOb25jZTE0 NzUxIiwiaWF0IjoxNTA2NDkyNTAyLCJpc3MiOiJodHRwczovL3Rlc3REZWYuY29tI iwic3ViIjoidGVzdHVzZXIiLCJleHAiOjE1MDY0OTYxMDIsIm15Q2xhaW0iOiJjbG FpbVZhbHVlIiwiYXVkIjoibXl0ZXN0Q2xpZW50In0.ZJdBmJtVw_Ti3Qjnpi21HWl Yk-asu72UnosYBZXeRn4
The decoded header:
{ "cty": "JWT", "alg": "HS256" }The claims:
{ "nonce": "someNonce14751", "iat": 1506492502, "iss": "https://testDef.com", "sub": "testuser", "exp": 1506496102, "myClaim": "claimValue", "aud": "mytestClient" }Retrieve Clients
We can retrieve the static and dynamic client data in the pre_token and post_token mapping rule, using the oauth_client variable.For example://The oauth_client varible will be unavailable during dynamic client registration in the pre_token mapping rule.
//Return the client id of the client
var client_id = oauth_client.getClientId();
//Return the client secret of the client
var client_secret = oauth_client.getClientSecret();
//Return the extended data associated with the client
var extendedData = oauth_client.getExtendedData();To customize the client_id and secret during a dynamic client registration flow, see OIDC Dynamic Clients- Custom Identifiers.
Dynamic Client Registration Flow
During dynamic client registration, the client id and client secret are either generated or can be customized. A variable is available in the pre and post token mapping rule to access the registered client and its attributes. For example:
//Return the client id of the dynamically registered client
var client_id = oauth_client.getClientId();
//Return the client secret of the dynamically registered client
var client_secret = oauth_client.getClientSecret();
//Return the extended data associated with the dynamically registered client
var extendedData = oauth_client.getExtendedData();
Parent topic: Mapping rules for OAuth and OIDC