Validating a pluggable token

This topic describes how to develop a Java Authentication and Authorization Service (JAAS) login module to authenticate the security token of an incoming request. The pluggable token is based on the JAAS programming model. You can develop and configure custom JAAS Login modules to authenticate custom security tokens.

See Configure a pluggable token for information about configuring the pluggable token authentication for a request receiver.

Standard login mapping configuration

WebSphere Application Server - Express provides default implementations and configurations of the following login mappings:

However, because the token is pluggable, you can can provide your own implementation. The token value is optional for the BasicAuth, Signature, and IDAssertion authentication methods. However, the token value is required by other types of authentication methods, including LTPA and the pluggable token. It is used to validate against the value type of binary security token (<wsse:BinarySecurityToken@ValueType>) and against the namespace for XML-based token. Therefore, the request sender must have the correct value type configured and inserted into the security tokens.

Developing a JAAS Login Module

The following figure shows the relationship between the login mapping configuration and the pluggable token validation.

Figure 1: Token validation

Token validation

The com.ibm.wsspi.wssecurity.auth.callback.CallbackHandlerFactory interface is a factory that is used to create an instance of the javax.security.auth.callback.CallbackHandler interface. For more information, see the Javadoc Link outside Information Center (http://java.sun.com/j2ee/sdk_1.3/techdocs/api/javax/security/auth/callback/CallbackHandler.html). The various set() methods are used by the Web services security run time to pass various security tokens (<wsse:UsernameToken>, <BinarySecurityToken>, and XML-based security token and properties from the login binding) to the implementation, which can pass the security tokens to the new callback handler instance. The properties defined for the CallbackHandlerFactory in the login mapping are passed to the implementation through the com.ibm.wsspi.wssecurity.auth.callback.CallbackHandlerFactory.init() method.

WebSphere Application Server - Express provides a default implementation of the CallbackHandlerFactory interface, which is called com.ibm.wsspi.wssecurity.auth.callback.WSCallbackHandlerFactoryImpl. The default implementation creates a callback handler that can handle the following javax.security.callback.Callback implementation classes:

com.ibm.wsspi.wssecurity.auth.module.WSSecurityMappingModule

WebSphere Application Server - Express also provides a default JAAS login module that you can use to map an identity to a principal and a credential. WebSphere Application Server - Express then can use the identity. The JAAS Login Module is called com.ibm.wsspi.wssecurity.auth.module.WSSecurityMappingModule. After the custom JAAS Login Module validates or authenticates the security token, the WSSecurityMappingModule can be used to map the identity to principal and credential format that can be used WebSphere Application Server - Express. You can configure the WSSecurityMappingModule module as the last JAAS login module in the JAAS login configuration using the stackable login module of JAAS. For more information on configuring a JAAS login, see Configure JAAS login in the Security topic.

The WSSecurityMappingModule.login() method looks for the identity using the com.ibm.wsspi.wssecurity.Constants.DN key from the shared state map (java.util.Map) of a JAAS login context. The shared state map is passed to the JAAS login module by the javax.security.auth.spi.LoginModule.initialize() method. After the credential is successfully created by the WSSecurityMappingModule.login() method, the WSSecurityMappingModule saves it in the shared state map by using the com.ibm.wsspi.wssecurity.Constants.WSCredential key. The other JAAS Login Modules can get the credential into their commit method. The credential is removed in the abort or commit method of the WSSecurityMappingModule.

Sample

The following sample code is a sample JAAS login module implementation that is used to validate the <wsse:BinarySecurityToken> element. The error handling was removed for clarity.

import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.spi.*;
import com.ibm.websphere.security.auth.callback.*;
import java.util.*;
import javax.security.auth.login.*;
import com.ibm.websphere.security.cred.*;
import com.ibm.wsspi.wssecurity.auth.callback.*;

public class MyBSTLoginModule implements LoginModule {
  private Subject subject;
  private CallbackHandler callbackHandler;
  private Map sharedState;
  private Map options;

  private boolean succeeded = false;
  private boolean commitSucceeded = false;

  private byte[] token = null;
  private Map properties = null;
  private WSCredential credential = null;

  public MyBSTLoginModule() {
  }

  public void initialize(Subject subject, CallbackHandler callbackHandler,
                         Map sharedState, Map options) {
    this.subject = subject;
    this.callbackHandler = callbackHandler;
    this.sharedState = sharedState;
    this.options = options;
  }

  public boolean login() throws LoginException {
    if (callbackHandler == null)
      throw new LoginException("No CallbackHandler");

    succeeded = false;

    Callback[] callbacks = new Callback[2];
    callbacks[0] = new WSCredTokenCallbackImpl("Cred token: ");
    callbacks[1] = new PropertyCallback(null);

    try {
      callbackHandler.handle(callbacks);
      token = ((WSCredTokenCallbackImpl) callbacks[0]).getCredToken();
      // get the property in Login Mapping
      properties = ((PropertyCallback) callbacks[1]).getProperties();
    } catch (java.io.IOException ioe) {
      throw new LoginException(ioe.toString());
    } catch (UnsupportedCallbackException uce) {
      throw new LoginException(uce.getCallback().toString());
    }

    // validate the token and extract the id from the token
    succeeded = validate(token);
    String id = extractId(token);
    // put the identity in shared state
    sharedState.put(com.ibm.wsspi.wssecurity.Constants.WSSECURITY_DN, id);
    
    // ....

    return succeeded;
  }

  public boolean commit() throws LoginException {
    commitSucceeded = false;

    if (succeeded == true) {
      // set the custom token in the subject ....
      // to get the websphere credential
      credential = (WSCredential) sharedState.get(com.ibm.wsspi.wssecurity.Constants.WSSECURITY_CRED);
      // ....
      commitSucceeded = true;
    } else {
      // error;
    }

    return commitSucceeded;
  }

  private boolean validate(byte[] t) {
    // validate token
    // ....
    return true;
  }
  
  private String extractId(byte[] t) {
    // extract token id
    // ....
    return ...;
  }

  public boolean abort() throws LoginException {
    cleanup();
    return true;
  }

  public boolean logout() throws LoginException {
    cleanup();
    return true;
  }

  private void cleanup() {
    succeeded = false;
    commitSucceeded = false;
    // cleanup
  }
}