12 Developing a Custom OAuth Plug-in

With OAM 12c, OAuth tokens can have claims defined using policy responses. As a result, claims can be defined in an OAuth client or resource server definition using the user session ($session) and LDAP entry ($user) namespaces. For example, you can specify $session.authn_level or $user.attr.givenname in the OAuth client configuration. There can be use cases where an OAuth token must have claims retrieved from an external source. For example, the token must have claims provided by a REST endpoint.

The requirement here is to retrieve claims and inject the three claims listed here into Issued OAuth (JWT) token. To achieve this we must use a custom responses plugin.
Claim name Claim value
my_plugin_claim1 myvalue1
my_plugin_claim2 myvalue2
my_plugin_claim3 myvalue3
The process of developing a custom response plugin involves following steps:
  1. Develop a custom response plugin
  2. Package and deploy the custom code as an OAM plugin
  3. Register a plugin for use in an identity domain
  4. Specify the custom claims in a client/resource server definition

Develop a Custom Response Plugin

The process of compiling a custom responses plugin is similar to a customer federation user provisioning plugin. For more information, see Developing a User Provisioning Plug-in.

Code snippets of OAuthCustomClaimsPlugin is as follows:
public class OAuthCustomClaimsPlugin extends ResponsesProviderPlugin{
  public ExecutionStatus initialize(PluginConfig config) {
        //Use initialization parameters for the plugin.
                super.initialize(config);
                
                //parameter REST_URL is not used. This is only for example. 
                Object tmp = config.getParameter("REST_URL");
                LOGGER.finer("OAuthCustomClaimsPlugin initialize REST_URL from configuration "+tmp);

                //If cacheResponsesInSession is false, responses will not be cached in user session. 
                cacheResponsesInSession = (String) config.getParameter("cacheResponsesInSession");
                LOGGER.finer("OAuthCustomClaimsPlugin initialize cacheResponsesInSession from configuration "+tmp);

                return ExecutionStatus.SUCCESS;
    }
@Override
        public ExecutionStatus execute(RequestContext requestContext, Responses responses) {
                Object[] params = {requestContext.getUserId(),
                                requestContext.getOAuthClientID(),requestContext.getOAuthClientName(),
                                requestContext.getOAuthIdentityDomain(),getAsString(requestContext.getScopes())};
                LOGGER.logp(Level.FINER, "OAuthCustomClaimsPlugin","execute",
                                "userID: {0} "
                                + "client id: {1} client name:{2} identity domain: {3} scopes:{4}", params);

                //Retrieve the custom claims
                //This is an example, in real world problem customer would write custom code to retrieve
                // the claims for a user from the REST_URL.
                responses.setResponse("myclaim1", "myvalue1");
                responses.setResponse("myclaim2", "myvalue2");
                responses.setResponse("myclaim3", "myvalue3");

                //Cache claims in session
                //By default, claims are not cached in the user session.
                //After user obtains a token from an authz code, user session can contain the claims returned by the plugin.
                //From an authz policy, this can be retrieved using $session.attr.<idDomain>.<pluginName>.<claimnamefromplugin>
                if(cacheResponsesInSession != null && cacheResponsesInSession.equalsIgnoreCase("true")){
                        LOGGER.finer("enabling cache  ");
                        responses.setCacheInUserSession(true);
                }

                return ExecutionStatus.SUCCESS;
        }

}

Claims Cached in the User Session

When enabled, claims retrieved by the plugin can be cached in the User's session as part of the Authorization Code flow in the following format:
$session.attr.<idDomain>.<pluginName>.<claimnamefromplugin>
For more information you can refer to the claims in the session namespace ($session) in a Policy Response, Client or Resource Server definition.

Note:

Caching of claims in the session that is, as session attributes are disabled by default. Session attributes will be populated with claims from the plugin only if plugin sets responses.setCacheInUserSession(true).

Package and Deploy the Custom Code as an OAM Plugin

  • The process of deploying a custom responses plugin is similar to a custom federation user provisioning plugin. For more information, see Developing a User Provisioning Plug-in.

  • Import, distribute, and activate the plugin in OAM console.

    Figure 12-1 Deploy Plugin


    Deploy Plugin

    Note:

    Plugins are executed in a sandbox (oSGi) that ensures isolation from the OAM Server at runtime.

Register a Plugin for use in an Identity Domain

The list of allowed plugins are defined at an identity domain level using customAttrs key-value pair as JASON string.

The following example shows payload of an identity domain update request:
{
    "name": "IDDomainName",
    "identityProvider": "oidoci",
    "description": "Updated Domain",
    "tokenSettings": [
        {
            "tokenType": "ACCESS_TOKEN",
            "tokenExpiry": 3600,
            "lifeCycleEnabled": false,
            "refreshTokenEnabled": true,
            "refreshTokenExpiry": 86400,
            "refreshTokenLifeCycleEnabled": false
        },
        {
            "tokenType": "AUTHZ_CODE",
            "tokenExpiry": 3600,
            "lifeCycleEnabled": false,
            "refreshTokenEnabled": true,
            "refreshTokenExpiry": 86400,
            "refreshTokenLifeCycleEnabled": false
        },
        {
            "tokenType": "SSO_LINK_TOKEN",
            "tokenExpiry": 3600,
            "lifeCycleEnabled": false,
            "refreshTokenEnabled": true,
            "refreshTokenExpiry": 86400,
            "refreshTokenLifeCycleEnabled": false
        }
    ],
    "errorPageURL": "/oam/pages/servererror.jsp",
    "consentPageURL": "/oam/pages/consent.jsp",
    "customAttrs": "{\"allowedCustomPlugins\":\"OAuthCustomClaimsPlugin\"}"
}

Specify Custom Claims in a Client or Resource Server Definition

Create OAuth client to use the above plugin. The payload of OAuth client creation contains reference to claim name, plugin name, and plugin attribute.
{
    "attributes": [
       {
        "attrName": "my_plugin_claim1",
        "attrValue": "$plugin.OAuthCustomClaimsPlugin.myclaim1",
        "attrType": "DYNAMIC"
        },{
        "attrName": "my_plugin_claim3",
        "attrValue": "$plugin.OAuthCustomClaimsPlugin.myclaim3",
        "attrType": "DYNAMIC"
        }
    ],
    "secret": "mysecret",
    "id": "OAuthClientID",
    "scopes": [
        "ResourceServer1.scope3","ResourceServer1.scope2","ResourceServer1.scope1"
    ],
    "clientType": "CONFIDENTIAL_CLIENT",
    "idDomain": "IDDomain",
    "description": "Client Description",
    "name": "OAuthClientName",
    "grantTypes": [
        "CLIENT_CREDENTIALS","PASSWORD","JWT_BEARER","REFRESH_TOKEN","AUTHORIZATION_CODE"
    ],
    "defaultScope": "ResourceServer1.scope1",
    "redirectURIs": [
        {
            "url": "http://localhost:8080/Sample.jsp",
            "isHttps": true
        }
    ],


........
........

}
Test 3-legged flow. After getting the user token from and authorization code, following access token is received:
{
    "iss": "http://oamserverhost:<OAM_WLS_MANAGEDSERVER_PORT>/oauth2",
    "aud": [
        "ResourceServer1",
        "http://oamserverhost:<OAM_WLS_MANAGEDSERVER_PORT>/oauth2"
    ],
    "exp": 1633332319,
    "jti": "mTswLkuKKMknpVcd_p9oEg",
    "iat": 1633328719,
    "sub": "user1",
    "client": "OAuthClientID",
    "scope": [
        "ResourceServer1.scope1"
    ],
    "domain": "IDDomain",
    "grant": "AUTHORIZATION_CODE",
     .......
    "my_plugin_claim3": "myvalue3",
    "my_plugin_claim1": "myvalue1",
     ......
}

Sample Screenshots

The following screen shows the use of cached custom claim in an authorization policy response.

Figure 12-2 Authorization Policy Response Screen


Authorization Policy Response Screen

The following screen shows CGI scripts printing the header information.

Figure 12-3 CGi Script Screen


CGi Script Screen