15 Developing a Custom Token Module

When Oracle Security Token Service does not support the token that you want to validate or issue out-of-the-box, you can write your own validation and issuance module classes. This chapter contains information on Oracle Security Token Service custom token options. It includes the following sections:

15.1 Introduction to Oracle Security Token Service Custom Token Module Classes

One of the two (validation or issuance class) is required for custom tokens:

  • The custom validation class, which is used to validate a custom token.

  • The custom issuance class, which is used to issue a custom token.

The following overview outlines the tasks you must perform.

Task overview: Deploying custom token module classes

  1. Writing a TokenValidatorModule Class to validate a custom token with Oracle Security Token Service, if needed.

  2. Writing a TokenIssuanceModule Class to issue a custom token with Oracle Security Token Service, if needed.

  3. Create a Custom Token module that will allow the user to create Validation Templates and Issuance Templates for their custom token. For more information, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

  4. Create Validation and Issuance Templates for the custom token, and use the custom templates in Endpoints and Partner Profiles as you would use the templates of standard tokens. For more information, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.

15.2 Writing a TokenValidatorModule Class

This section provides the following topics:

15.2.1 About Writing a TokenValidatorModule Class

The Oracle Security Token Service Validation module class implements the oracle.security.fed.sts.token.tpe.TokenValidatorModule interface. The following properties can be fetched from the TokenContext during the validation process:

  • XML_TOKEN: The bytes of the XML message that contains the token that must be validated.

  • BST_VALUE_TYPE: If the custom token is sent as a Binary Security Token, this will contain the Binary Security Token value type.

  • BST_ENCODING: If the token is sent as a Binary Security Token, this will contain the encoding.

  • BST_CONTENT: If the token is sent as a Binary Security Token, this will contain the Binary Security Token content.

  • TOKEN_ELEMENT: If the token is not a Binary Security Token and does not have a JAXB representation in the Oracle Security Token Service internal classes, this will contain the XML element or custom JAXB class representing the token.

  • XML_DOM: This is the DOM representation of the incoming message. This will be present only if a DOM object was created as a part of Oracle Security Token Service processing thus far.

The token should be validated using the information in the properties in the TokenContext and a TokenResult should be returned. The following properties can be set on a TokenResult object to return information to Oracle Security Token Service:

  • TPE_RESULT_FAILURE_CODE: The failure code if there was a failure.

  • TPE_RESULT_FAILURE_STRING: A string describing the failure.

  • Any other properties that are set in the result are available in the context to be used for token mapping. Usually, validators set STS_SUBJECT_ID property to the name ID and use this to map to a user record.

Example 15-1 EmailTokenValidatorModuleImpl.java

package oracle.security.fed.sts.tpe.providers.email;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import oracle.security.fed.sts.token.tpe.TokenContext;
import oracle.security.fed.sts.token.tpe.TokenProcessingException;
import oracle.security.fed.sts.token.tpe.TokenResult;
import oracle.security.fed.sts.token.tpe.TokenValidatorModule;
import oracle.security.fed.sts.token.tpe.TokenResultImpl;
import oracle.security.fed.sts.tpe.providers.TokenValidationErrors;
import oracle.security.fed.xml.security.wss.ext.v10.BinarySecurityTokenType;
import oracle.security.fed.util.common.Base64;
import sun.misc.BASE64Decoder;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
 
public class EmailTokenValidatorModuleImpl implements TokenValidatorModule{
    
    private Map options = null;    
    private String testSetting = null;
    
    private static final String TEST_SETTING_IN_TEMPLATE = "testsetting";
 
    public void init(Map options1) throws TokenProcessingException{
        
        options = options1;
        try{
            testSetting = (String)options.get(TEST_SETTING_IN_TEMPLATE);
           }catch(Exception e){
            throw new TokenProcessingException(e);                      
        }
        
    }
    
    public TokenResult validate(TokenContext context) throws TokenProcessingException{
        
        byte[] tokenBytes = (byte[])context.getOtherProperties().get("XML_TOKEN");
        Document inputDocument = (Document)context.getOtherProperties().get("XML_DOM");
        
        
        Element tokenElement = (Element)context.getOtherProperties().get("TOKEN_ELEMENT");
        String encodedBytes = (String) context.getOtherProperties().get("BST_CONTENT");
        byte[] decodedBytes = null;
        BASE64Decoder decoder = new BASE64Decoder();
       try{
        if(encodedBytes != null){
                decodedBytes = decoder.decodeBuffer(encodedBytes);
        }
        }catch(java.io.IOException exp){
         exp.printStackTrace();
        }
                        
        
        if(tokenElement != null && tokenElement.getLocalName().equals("email")){
            String emailAddress = tokenElement.getTextContent();
            TokenResultImpl result = null;
            result = new TokenResultImpl(0, TokenResult.SUCCESS, null);
            result.setTokenProperty("STS_SUBJECT_ID", emailAddress);
            
            //add any other attributes - necessary only if you need for mapping or issuance
            result.setTokenProperty("testattr2", "attr2");
           
            return result;
        }else if (decodedBytes != null) {
            String emailAddress = new String(decodedBytes);
            TokenResultImpl result = null;
            result = new TokenResultImpl(0, TokenResult.SUCCESS, null);
            result.setTokenProperty("STS_SUBJECT_ID", emailAddress);
            
            //add any other attributes - necessary only if you need for mapping or issuance
            result.setTokenProperty("testattr2", "attr2");
           
            return result;
 
        } else {
            TokenResultImpl result = new TokenResultImpl(0, TokenResult.FAILURE, null);
            String failureCode = null;
            failureCode = "TEST_FAILURE_CODE";
           
            result.setTokenProperty("TPE_RESULT_FAILURE_CODE", failureCode);
            result.setTokenProperty("TPE_RESULT_FAILURE_STRING", "validation failed");        
            return result;
        }
        
       
    }
}

The following overview outlines development highlights for this module class.

Development highlights: Writing a TokenValidatorModule class

  1. Implement the init(Map options) method, called when the TokenValidatorModule is initialized. The init method is passed in a map containing the parameters defined in the validation template.

  2. Implement the validate(TokenContext context) method, called when a particular incoming custom token must be validated.

    1. Fetch token information from the properties in the TokenContext object.

    2. Validate the token and return a TokenResult object:

      On Success, return:

      TokenResultImpl result = new TokenResultImpl(0, TokenResult.SUCCESS, token);
      

      On Failure, return:

      TokenResultImpl result = new TokenResultImpl(0, TokenResult.FAILURE, token);
      result.setTokenProperty("TPE_RESULT_FAILURE_CODE", failureCode);
      result.setTokenProperty("TPE_RESULT_FAILURE_STRING", "validation failed");
         
      
    3. Confirm the validated token result returns the SubjectID in the token and any attributes that are parsed from the token, in the following format:

      result.setTokenProperty("STS_SUBJECT_ID", emailAddress);
      
      //add any other attributes - necessary only if you need for mapping or issuance
      result.setTokenProperty("testattr2", "attr2")
      

15.2.2 Writing a TokenValidatorModule Class

Perform the following tasks to write a custom TokenValidatorModule class.

Task overview: Writing a TokenValidatorModule class

  1. Develop your own module class while referring to:

  2. Proceed as needed:

15.3 Writing a TokenIssuanceModule Class

This section provides the following topics:

15.3.1 About Writing a TokenIssuanceModule Class

The EmailTokenIssuerModuleImpl.java class should implement the oracle.security.fed.sts.token.tpe.TokenIssuerModule interface and attributes in the TokenContext.

Example 15-2 provides and example of EmailTokenIssuanceModuleImpl class. The overview that follows outlines development highlights for this module class.

Example 15-2 EmailTokenIssuanceModule.java

package oracle.security.fed.sts.tpe.providers.email;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
 
import javax.xml.namespace.QName;
 
import oracle.security.fed.sts.token.tpe.TokenContext;
import oracle.security.fed.sts.token.tpe.TokenIssuerModule;
import oracle.security.fed.sts.token.tpe.TokenProcessingException;
import oracle.security.fed.sts.token.tpe.TokenResult;
import oracle.security.fed.sts.token.tpe.Token;
import oracle.security.fed.sts.token.tpe.TokenImpl;
import oracle.security.fed.sts.token.tpe.TokenResult;
import oracle.security.fed.sts.token.tpe.TokenResultImpl;
 
public class EmailTokenIssuerModuleImpl implements TokenIssuerModule{
    
    Map config; 
    
    private static final String TEST_SETTING_IN_TEMPLATE = "testsetting";
 
    
    public void init(Map options) throws TokenProcessingException
    {
       config = options;
    }
    public TokenResult issue(TokenContext context) throws TokenProcessingException
    {       
        //use any config options necessary for processing from issuance template
        String setting = (String)config.get(TEST_SETTING_IN_TEMPLATE);
        
        
        HashMap attributes = (HashMap)context.getOtherProperties().get("STS_TOKEN_ATTRIBUTES");
        System.out.println("attributes : " + attributes.toString());
        String emailAddress = null;
        Iterator attrIter = null;
        if (attributes != null) {
            attrIter = attributes.keySet().iterator();        
        }
        if (attrIter != null) {
            while (attrIter.hasNext()) {
                String attributeName = (String)attrIter.next();
                if ("mail".equals(attributeName)) {
                    Object valuesObj = attributes.get(attributeName);
                    if (valuesObj instanceof List){
                        Iterator iter = ((List)valuesObj).iterator();
                            
                        while (iter.hasNext()) {
                            Object valueObj = iter.next();
                            if(valueObj instanceof String){
                                emailAddress = (String)valueObj;
                                break;
                            }
                        }
                    } else if (valuesObj instanceof String) {
                        emailAddress = (String)valuesObj;
                    }
                }
            }
        }
            
        String email = "<email>" + emailAddress + "</email>";
        System.out.println("email : " + email);
        TokenImpl token = new TokenImpl();
        byte[] tokenBytes = email.getBytes();
        
        token.setTokenBytes(tokenBytes);
        //set the below if you have a doc object that can be reused
        token.setTokenDocument(null);
        
        
        token.setTokenBytes(tokenBytes);
        TokenResultImpl result = new TokenResultImpl(0, TokenResult.SUCCESS, token);
        Map resultMap = new HashMap();
              resultMap.put("STS_KEY_IDENTIFIER_VALUE", emailAddress);
              resultMap.put("STS_KEY_IDENTIFIER_VALUE_TYPE", "EmailAddress");
               System.out.println("TOKEN_KEY_IDENTIFIER_VALUE  :  " + emailAddress);
 
              
              result.setTokenProperties(resultMap);
        return result;
   
    }
 
}

Development highlights: Writing a TokenIssuanceModule class

  1. Implement the public void init(Map options)throws TokenProcessingException method.

    The init() method is called when the issuer module is initialized. The init method is passed a map contain the parameters defined in the issuance template.

  2. Implement the public TokenResult issue(TokenContext context) throws TokenProcessingException method.

    This method is called when a custom outgoing token must be created.

    1. Create, within the issue method, the token using the attributes in the issuance template and the attributes passed in the TokenContext. Attributes in the TokenContext are accessed in the following way:

      HashMap attributes = (HashMap)context.getOtherProperties().get("STS_TOKEN_ATTRIBUTES");
      System.out.println("attributes : " + attributes.toString());
      String emailAddress = null;
      Iterator attrIter = null;
      if (attributes != null) {
      attrIter = attributes.keySet().iterator();
      }
       
      if (attrIter != null) {
      while (attrIter.hasNext()) {
      String attributeName = (String)attrIter.next();
      if ("mail".equals(attributeName)) {
      Object valuesObj = attributes.get(attributeName);
      if (valuesObj instanceof List){
      Iterator iter = ((List)valuesObj).iterator();
       
      while (iter.hasNext()) {
      Object valueObj = iter.next();
      if(valueObj instanceof String){
      emailAddress = (String)valueObj;
      break;
      }
      }
      } else if (valuesObj instanceof String) {
      emailAddress = (String)valuesObj;
      }
      }
      }
      }
      Status  
      
    2. Create a result object and set the bytes of the token and the Document Object Model (DOM) representation of the token (only if the DOM representation was created during the processing in this class):

      token.setTokenDocument(null);--> if you have a doc object that can be reuse.d set it here
      token.setTokenBytes(tokenBytes);
      TokenResult result = new TokenResultImpl(0, TokenResult.SUCCESS, token); 
      
    3. Set the key identifier information into the token properties, as follows:

      Map resultMap = new HashMap();
         resultMap.put("STS_KEY_IDENTIFIER_VALUE", emailAddress);
         resultMap.put("STS_KEY_IDENTIFIER_VALUE_TYPE", "EmailAddress");
         result.setTokenProperties(resultMap);
      

Note:

The attributes set as token properties are available in the context. The attributes can be used for token mapping or can be specified in the relying party profile attributes section for inclusion in the outgoing token in the usual way.

15.3.2 Writing a TokenIssuanceModule Class

Task overview: Writing an Issuance Module class

  1. Write the issuance module class as you refer to Section 15.3.1, "About Writing a TokenIssuanceModule Class" and Oracle Fusion Middleware Java API Reference for Oracle Access Management Security Token Service.

  2. For information about managing a custom Security Token Service configuration, see Oracle Fusion Middleware Administrator's Guide for Oracle Access Management.