JavaScript Mapping rule reference

JavaScript mapping rule

This document covers all the interfaces available for mapping rule JavaScript.

1. STSUniversalUser

The general rule of STSUniversalUser is that, the authenticated user claims are available under the AttributeContainer section and request parameters are available under the ContextAttribute section.

Return TypeMethodDescriptionArguments
AttributeContainergetAttributeContainer()Return the AttributeContainer section.
AttributeContainergetContextAttributes()Return the ContextAttribute section.
addAttribute(attr)Add attribute into AttributeContainer section.Attribute
addContextAttribute(attr)Add attribute into ContextAttribute section.Attribute
getAttributeValueByName(name)Retrieve attribute from AttributeContainer section.string
setPrincipalName(name)Set principal name.string
stringgetPrincipalName()Retrieve principal name.
stringtoString()Stream STSUniversalUser to JSON string.

1.1. Attribute

Return TypeMethodDescription
stringgetName()Return attribute's name.
stringgetType()Return attribute's type.
anygetValue()Return attribute's value.
any[]getValues()Return attribute's values.

1.2. AttributeContainer

Return TypeMethodDescriptionArguments
AttributegetAttributeByName(name)Return attribute that matches the name that was provided.string
Attribute[]getAttributeByType()Return attributes that match the type that was provided.string
AttributegetAttributeByNameAndType(name, type)Return attribute that matches the name and type that were provided.string, string
anygetAttributeValueByName(name)Return first value of the attribute that matches the name that was provided.string
any[]getAttributeValuesByName(name)Return all values of the attribute that match the name that was provided.string
anygetAttributeValueByNameAndType(name, type)Return first value of the attribute that matches the name and type that were provided.string, string
any[]getAttributeValuesByNameAndType(name, type)Return all values of the attribute that match the name and type that were provided.string
any[]setAttributeObject(attr)Set attribute into the attribute container.Attribute
any[]setAttribute(name, type, values)Create an attribute in the attribute container with the value that was provided.string, string, any
AttributeremoveAttributeByNameAndType(name, type)Remove attribute based on name and type that were provided.string, string
BooleanremoveAttribute(attr)Remove the specified attribute from the container.Attribute

2. Client and definition

In the mapping rule javascript, Client and Definition objects
are available under oauth_client and oauth_definition, respectively.

3. PreToken mapping rule

Pre-token mapping rule is used to enrich the tokens, meaning that it produces claims that are output in the id_token or /userinfo endpoint.
It also produces claims that are presented when tokens are introspected at the /introspect endpoint.

This approach is a slightly different than what is in ISVA.
In the JavaScript context, two JS map objects are displayed: tokenData and idtokenData.

To enrich the id_token and /userinfo endpoints, assign a name-value pair into the idtokenData object.
And to enrich the /introspect endpoint - which can also be used for JWT access token - assign name-value pair into the tokenData object.

The advantage of this approach is the claim can be a complex object and no longer limited by STSUniversalUser string data type only.

Example usage:

  var hok = {
      "fingerprint#256": "aalweuaadg27ifafw8a2"
  }
  var grps = ["admin", "user"];
  tokenData.cnf = hok;
  tokenData.groups = grps;

3.1. Attribute mappings

In Definition, a user can define attribute mappings. Before the pre-token mapping rule is called, all attribute mappings are resolved, and the data (if any)
is available in the AttributeContainer section of the STSUniversalUser object.

3.2. Requested claims

To be able to do claim mapping, the user needs to know what claims are requested. According to OIDC specification, the claims can be requested by using scope values or requested by using claims parameter.

To make this process easier, the system considers both parameters and displays a claims object of type RequestedClaims
that has the following interface:

Return TypeMethodDescriptionArguments
string[]getIDTokenEssentialClaims()Return ID token essential claims.
string[]getIDTokenVoluntaryClaims()Return ID token voluntary claims.
string[]getUserInfoEssentialClaims()Return user information essential claims.
string[]getUserInfoVoluntaryClaims()Return user information voluntary claims.
string[]getAllClaims()Return all claims.
string[]getIDTokenClaimValues(name)Return values associated with an ID token claim.string
string[]getUserInfoClaimValues(name)Return values associated with a user information claim.string

For example, given scope=openid+email+phone and claims parameter as follows:

{
  "userinfo": {
    "given_name": { "essential":true },
    "nickname": { "essential": false, "value": "Joe" },
    "email": { "essential": true },
    "http://example.info/claims/groups":null
  },
  "id_token": {
    "given_name": { "essential": false },
    "auth_time": { "essential": true },
    "acr": { "values": [ "urn:mace:incommon:iap:gold", "urn:mace:incommon:iap:silver" ] }
  }
}

Based on the previous example:

  • claims.getIDTokenEssentialClaims() returns ["auth_time"]
  • claims.getAllClaims() returns ["acr", "nickname", "email", "http://example.info/claims/groups", "phone_number", "phone_number_verified", "auth_time", "email_verified","given_name"].
  • claims.getIDTokenClaimValues("acr") returns ["urn:mace:incommon:iap:gold", "urn:mace:incommon:iap:silver"]
  • claims.getUserInfoClaimValues("nickname") returns ["Joe"]

4. PostToken mapping rule

Post-token mapping rule is the last chance to manipulate the response.

Similar to pre-token mapping rule, in the JavaScript context, two JS map objects displayed: tokenData and idtokenData.
The tokenData object contains the claim for introspect and the idtokenData object contains the claim for id_token/userinfo that were done in the pre-token mapping rule.

User can manipulate extra parameters or extra headers in the response. For that purpose, two JS map objects are displayed: paramsOverride and headersOverride.
The paramsOverride value can be of complex type because it can go to the query string, fragment, or response body.
The headersOverride value must be kept as string because it goes to the response header.

Example usage:

  headersOverride["x-fapi-corr-id"] = "gsdu2-22y2haw-23nafa-afw";

5. Extra mapping rules

Due to a different code structure, in IBM Security Verify Access OIDC Provider(ISVAOP) mapping rules are intended for specific purposes.

5.1. ROPC user authentication

In ISVA, the user authentication for ROPC is done in the pre-token mapping rule. In the ISVAOP, the mapping rule ropc.js performs the task.
The username and password that are received from the request are available in STSUniversalUser ContextAttribute. When the user is authenticated, the claims that are related to the user are set into the JS map object userData.

Example usage:

var username = stsuu.getContextAttributes().getAttributeValueByName("username");
var password = stsuu.getContextAttributes().getAttributeValueByName("password");

if (username == "peter" && password == "secret") { // Authenticate user via LDAP or HTTP call-out
    userData.uid = "prabbit"; // This will be the `sub` of the token
    userData.given_name = "peter";
    userData.family_name = "rabbit";
    userData.preferred_username = "[email protected]";
} else {
    OAuthMappingExtUtils.throwSTSInvalidGrantMessageException("Invalid user or password.", "Either user or password is not valid.");
}

5.2. Dynamic client registration metadata customization

In ISVA, the pre-token mapping rule is also used to manipulate the dynamic client registration payload for the following use cases:

  • Setting the defaults for metadata that are not specified in the incoming payload. For example, if grant_types is not specified, the default is authorization_code.
  • Substitute metadata values that the OIDC provider does not support or wants to enforce. For example, the OIDC provider might want to enforce the token_endpoint_auth_method to private_key_jwt only.
  • Further metadata validation. For example, in OpenBanking specification, some metadata needs to be bound by metadata inside the software statement. Other examples are to check software statement issuer, expiry, or other attributes.
  • Throws an invalid_client_metadata error for metadata values that the OIDC provider does not like.

In ISVAOP, this goes to separate javascript file that can be configured in the provider.yml.
Definition object should be available under oauth_definition context.
Each client metadata received is available as attributes under ContextAttribute section.

Example usage:

// Setting default example
var grant_types = stsuu.getContextAttributes().getAttributeValuesByName("grant_types");
if (grant_types == null) {
    stsuu.addContextAttribute(new Attribute("grant_types", "urn:ibm:names:ITFIM:oauth:body:param", "authorization_code"));
}

// Substitute metadata value example
var attr = stsuu.getContextAttributes().getAttributeByName("token_endpoint_auth_method");
if (attr != null) {
    stsuu.getContextAttributes().removeAttribute(attr);
}
stsuu.addContextAttribute(new Attribute("token_endpoint_auth_method", "urn:ibm:names:ITFIM:oauth:body:param", "private_key_jwt"));

// Further metadata validation
var ss = stsuu.getContextAttributes().getAttributeValueByName("software_statement");
if (ss != null) { // Software statement exists
    var iss = stsuu.getContextAttributes().getAttributeValueByName("iss");
    if (iss != "http://openbankingdirectory.com") {
        OAuthMappingExtUtils.throwSTSCustomUserMessageException("Unexpected software statement issuer.", 400, "invalid_client_metadata");
    }
}

6. Differences between ISVAOP and ISVA-mapping rules

6.1. Differences in purposes

In ISVA, the pre-token and post-token mapping rules can be interpreted as user customization before and after the default implementation that is done in OAuth20TokenModule. Therefore, the user authentication for the ROPC flow and the id_token claims that need to be resolved, must be done inside pre-token mapping rule before the token can be generated. Because the state_id, also called the grant_id, is available only after token is generated, the association of extra data happens at post-token. Also, post-token is used to manipulate the final result, for example, in the introspection and userinfo endpoints. Although technically the manipulation can be done at pre-token because the default implementation produces only a minimal response that unlikely needs to be overwritten.

In ISVAOP, as explained in PreToken Mapping Rule, PostToken Mapping Rule, and Additional Mapping Rules, each mapping rule can have different purpose. Therefore, some refactoring is needed.

  • ROPC user authentication goes to a specific mapping rule.
  • Introspect enrichment is done in pre-token instead of post-token.
  • Userinfo enrichment is done together with id_token in the pre-token.
  • Dynamic Registration defaults, overrides, and further validation go to another mapping rule.

Also, things that currently are done in the mapping rules are now available OOTB or through configuration. For examples:

  • The enforcement that authorization code can be used only once.
  • Filtering of scopes
  • Enforcement of jti uniqueness
  • Validation of various JWTs

6.2. Differences in objects

Some of the differences are:

  • Definition object is displayed by default as oauth_definition.
  • Java List and Map are replaced with a JS list and object, so some interfaces that are available as part of that Java might no longer be there.
  • The introduction of new objects such as claims, userData, tokenData, paramsOverride.