ISAM Context Based Access PIP for OAuth

The vast majority of the work in developing this PIP was done by my colleague Scott Andrews. Thanks for sharing Scott! Find more of his work here:
https://ibm.biz/securityintegration

Building from the example PIP in my article here: ISAM JavaScript Policy Information Points here is a PIP that extracts the OAuth values of scope and supplies them to the CBA engine as a multi valued attribute. Note: This mechanism is dependent on the use of the OAuth-Auth mechanism (as defined here: OAuth Authentication and Sessions)

The PIP is necessary for the scope attribute as the attribute that is defined in the ISAM credential is supplied as a single string “scope1,scope2,scope3” that is comma separated. This PIP will tokenize them and supply them as a proper multivalued attribute for easy policy authoring. The untokenized Scope attribute is available already, and it’s defined as: oauthScopeSubject.

It also extracts the OAuth Client ID which can be useful in other OAuth focused authorization policies.

One example of using the client ID attribute:
Only the iOS client can access these API’s while the Android application should be blocked.
This client ID is defined in the API Definition page:

Step 1) Create two new CBA Attributes:

Name: OAuth Scope
Identifier: urn:ibm:security:iam:oauth:scope
Issuer: OAuthPIP
Category: Subject
Data Type: String
Matcher: exact_match
Type: Policy

Scope

Name: OAuth ClientID
Identifier: urn:ibm:security:iam:oauth:client:id
Issuer: OAuthPIP
Category: Subject
Data Type: String
Matcher: exact_match
Type: Policy

Note: The Issuer should match the name you define when creating the JavaScript PIP in the next step.

If you wanted to use these attributes in a Risk Score calculation, you could also select the Type “Risk”.

Step 2) Create the JavaScript PIP:

Start with the standard imports:

importPackage(com.tivoli.am.rba.extensions);
importClass(Packages.com.tivoli.am.rba.attributes.AttributeIdentifier);

As per the JavaScript PIP guide, there are two main functions, hasAttribute:

function hasAttribute (requestedAttribute, category) {

    PluginUtils.trace("oauthscope_pip_rile.hasAttribute(): entry");
    PluginUtils.trace("oauthscope_pip_rile.hasAttribute(): Looking for " 
        + requestedAttribute + " in " + category);
    // The 'instanceName' global variable should match the issuerId 
    // configured for the attributes.  
    var issuerId = instanceName;

    var pipIssued = false;

    if (issuerId.equals(requestedAttribute.getIssuer()))
    {
         pipIssued = true;
    }       

    PluginUtils.trace("oauthscope_pip_rile.hasAttribute(): exit: " 
        + requestedAttribute.getURI() + " --> returning " + pipIssued);

    return pipIssued;
}

and getAttributes:

function getAttributes (context, requestedAttribute, category) {

    PluginUtils.trace("oauthscope_pip_rile.getAttributes(): entry: " 
        + requestedAttribute + " --> " + category);
    
    /**
     * In case our PIP serves more than 1 attribute, let's still check 
     * for the one we're looking for
     */
    if ("urn:ibm:security:iam:oauth:scope".equals(requestedAttribute.getURI())) { 
        
        /**
         * Get the oauthScopeSubject attribute.  Note if we are using the 
         * EAS instead of oauth-auth in WebSEAL, we would instead get the 
         * oauthScopeResource attribute and lookin the RESOURCE attribute 
         * not the SUBJECT.
         */
        var oauthScopeSubjectIdentifier = new AttributeIdentifier(
            "urn:ibm:security:subject:oauthScope",
            Attribute.DataType.STRING,
            null);
    
        var oauthScopeSubject = context.getAttribute(Attribute.Category.SUBJECT, 
            oauthScopeSubjectIdentifier);   
    
        if (oauthScopeSubject != null && oauthScopeSubject.length > 0) { 
            PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " 
              + "Found scopes: " + oauthScopeSubject[0]);
            
        /**
         * Try a cast so we don't try and do it on an Object data type 
         * otherwise you get a Java Object exception.
         */
        var    stringScopeCast = String(oauthScopeSubject[0]);
        
        //Turn our static string into a multi valued attribute.  Make an 
        // assumption of no whitespace. 
        var oauthScopes = stringScopeCast.split(",")
        
        /**
         * Create the new attribute identifier to populate it back 
         * into the context.
         *
         * Instance name is the name of the PIP, so we can use this *but* if 
         * we have a PIP that is the issuer for multiple issuer IDs, 
         * we couldn't use it as the hasAttribute would have checked against 
         * 1 or more and then manually returned true.         
         */
        var oauthScopeAttribute = new AttributeIdentifier(
            "urn:ibm:security:iam:oauth:scope",
            Attribute.DataType.STRING,
            instanceName);
    
        context.addAttribute(oauthScopeAttribute, oauthScopes);
        
        PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " 
            + "adding urn:ibm:security:iam:oauth:scope " + oauthScopes);
            
        }        
        else {
            PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " + 
                "No oauthScopeSubject found!");
        }        
    }

    if ("urn:ibm:security:iam:oauth:client:id"
              .equals(requestedAttribute.getURI())) {    
                
        /**
         * Retrieve the oauth_token_client_id from the XACML passed from 
         * WebSEAL to RTSS. You can find a list of additional attributes you 
         * could use by looking in the pdweb.rtss.
         * For example - 
         * access_token
         * client_type
         * scope (though already an attribute which is populated from 
         * urn:ibm:security:subject:oauthScope which is also sent)
         * urn:oasis:names:tc:xacml:1.0:action:action-id (though already in 
         * the attribute list as the 'action' which is the HTTP Method)
         */
        var oauthClientIdIdentifier = new AttributeIdentifier(
            "oauth_token_client_id",
            Attribute.DataType.STRING,
            null);
    
        var oauthClientId = context.getAttribute(Attribute.Category.SUBJECT, 
            oauthClientIdIdentifier);   
        
        if (oauthClientId != null && oauthClientId.length > 0) { 
            PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " + 
            "Found oauth_token_client_id: " + oauthClientId[0]);
            
            var oauthClientIdAttribute = new AttributeIdentifier(
                "urn:ibm:security:iam:oauth:client:id",
                Attribute.DataType.STRING,
                instanceName);
        
            context.addAttribute(oauthClientIdAttribute, [oauthClientId[0]]);
            
            PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " + 
                "adding urn:ibm:security:iam:oauth:client:id " 
                     + [oauthClientId[0]]);        
        
        }
        else {
            PluginUtils.trace("oauthscope_pip_rile.getAttributes(): " 
                + "No oauth_token_client_id found!");
        }        
    }    
    
    PluginUtils.trace("oauthscope_pip_rile.getAttributes(): exit");
}

Save in your favorite editor, and create and upload your PIP

Name: OAuthPIP
Description: Parses the scope and ClientID OAuth attributes and makes them available for simple CBA policies
Type: JavaScript
Script: <Upload your file>

OAuthPIP

Step 3) Use your attribute in your CBA policy and profit!

One thought on “ISAM Context Based Access PIP for OAuth

Add yours

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

WordPress.com.

Up ↑

%d bloggers like this: