Generating a dynamic UsernameToken using a stacked JAAS login module

You can use the GenericSecurityTokenFactory APIs to create fully-populated or simple UsernameToken security tokens for use by the WS-Security runtime. These security tokens can be used for, but are not be limited to, WSSAPIs, and JAAS login modules, or UNTGenerateLoginModule.

About this task

The GenericSecurityTokenFactory provides several APIs that you can use to create UsernameTokens that can be emitted with the GenericIssuedTokenGenerateLoginModule.

There are two types of UsernameTokens:
Full UsernameToken
A full UsernameToken contains XML and can be emitted with the GenericSecurityTokenFactory login module.
Simple UsernameToken
A simple UsernameToken contains only a user name and password; it does not contain XML. Simple UsernameTokens are used to set a dynamic username and password that the UNTGenerateLoginModule, LTPAGenerateLoginModule, and KRBGenerateLoginModule can use.

When a full UsernameToken is created using a GenericSecurityTokenFactory API, the token is the complete form of a security token that can be emitted by the WS-Security run time. Determine the type of token you want to create, and then issue commands, similar to the ones specified in one of the following steps, to create your token. After the token is created, the user name and password in the token cannot be modified.

When a simple UsernameToken is created using a GenericSecurityTokenFactory API, the token contains only the user name and optionally the password. Because a simple UsernameToken does not contain XML, it cannot be emitted with the GenericIssuedTokenGenerateLoginModule.

Procedure

  1. Create a UsernameToken.
    You can create one of the following types of UsernameToken:
    • A full UsernameToken with a user name and password
    • A full UsernameToken with a user name and timestamp, but no password
    • A simple UsernameToken with a user name and password
    • Create a full UsernameToken with a user name and password.
      import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
      import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
      
      ...
      
      GenericSecurityTokenFactory gstFactory = GenericSecurityTokenFactory.getInstance();
      UsernameToken myUnt = gstFactory.getFullUsernameToken("myUsername", "myPassword".toCharArray());
    • Create a full UsernameToken with a user name and timestamp, but no password.
      import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
      import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
      
      ...
      
      GenericSecurityTokenFactory gstFactory = GenericSecurityTokenFactory.getInstance();
      UsernameToken myUnt = gstFactory.getFullUsernameToken("myUsername", null, true);
    • Create a simple UsernameToken with a user name and password.
      import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
      import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
      ...
      GenericSecurityTokenFactory gstFactory = GenericSecurityTokenFactory.getInstance();
      UsernameToken myUnt = gstFactory.getSimpleUsernameToken("myUsername", "myPassword".toCharArray());
  2. Create a JAAS login module.
    If you created a full UsernameToken in the previous step, you must create a JAAS login module that can be stacked on top of GenericIssuedTokenGenerateLoginModule to emit a full UsernameToken. If you created a simple UsernameToken in the previous step, you must create a JAAS login module that can be stacked on top of UNTGenerateLoginModule to emit a dynamic UsernameToken.
    • Create a JAAS login module that can be stacked on top of GenericIssuedTokenGenerateLoginModule to emit a full UsernameToken.
      The following example applies if you are using Version 8.5.0.2 or later:
      package test.tokens;
      
      import java.util.HashMap;
      import java.util.Map;
      
      import javax.security.auth.Subject;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.login.LoginException;
      import javax.security.auth.spi.LoginModule;
      import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
      import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
      import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
      import com.ibm.wsspi.wssecurity.core.config.CallbackHandlerConfig;
      
      import java.util.ArrayList;
      
      public class MyFullUntGenerator implements LoginModule {
      
        private Map _sharedState;
        private Map _options;
        private CallbackHandler _handler;
      
        public void initialize(Subject subject, CallbackHandler callbackHandler,
                               Map<String, ?> sharedState, Map<String, ?> options) {
      
          this._handler = callbackHandler;
          this._sharedState = sharedState;
          this._options = options;  
        }
      
        public boolean login() throws LoginException {
          //For the sake of readability, this login module does not
          //protect against all NPE's
      
          GenericSecurityTokenFactory factory = null;
          try {
            factory = GenericSecurityTokenFactory.getInstance();
          } catch (Exception e) {
            throw new LoginException(e.toString());
          }
          if (factory == null) {
            throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
          }
      
          //The userid and password can be obtained however you want
      
          // (Optional) Obtain the username and password configured in the callback handler
          Map wssContext = getWSSContext(_handler);            
          CallbackHandlerConfig chc = (CallbackHandlerConfig) wssContext.get(CallbackHandlerConfig.CONFIG_KEY);    
                                                           
          String username = chc.getUserId();                   
          char[] password = chc.getUserPassword();   
      
          UsernameToken unt = factory.getFullUsernameToken("myUsername", "myPassword".toCharArray());
      	
          //Put the token in a list on the shared state where it will be available to be used by
          //stacked login modules
          factory.putGeneratorTokenToSharedState(_sharedState, unt);
      
          return true;
        }
        //implement the rest of the methods required by the
        //LoginModule interface
      }
    • Create a JAAS login module that can be stacked on top of UNTGenerateLoginModule to emit a dynamic UsernameToken
      package test.tokens;
      
      
      import java.util.HashMap;
      import java.util.Map;
      
      import javax.security.auth.Subject;
      import javax.security.auth.callback.CallbackHandler;
      import javax.security.auth.login.LoginException;
      import javax.security.auth.spi.LoginModule;
      import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
      import com.ibm.websphere.wssecurity.wssapi.token.UsernameToken;
      import com.ibm.websphere.wssecurity.wssapi.WSSUtilFactory;
      import com.ibm.wsspi.wssecurity.core.config.CallbackHandlerConfig;
      
      import java.util.ArrayList;
      
      public class MySimpleUntGenerator implements LoginModule {
      
        private Map _sharedState;
        private Map _options;
        private CallbackHandler _handler;
      
        public void initialize(Subject subject, CallbackHandler callbackHandler,
                               Map<String, ?> sharedState, Map<String, ?> options) {
      
          this._handler = callbackHandler;
          this._sharedState = sharedState;
          this._options = options;  
        }
      
        public boolean login() throws LoginException {
          //For the sake of readability, this login module does not
          //protect against all NPE's
      
          GenericSecurityTokenFactory factory = null;
          try {
            factory = GenericSecurityTokenFactory.getInstance();
          } catch (Exception e) {
            throw new LoginException(e.toString());
          }
          if (factory == null) {
            throw new LoginException("GenericSecurityTokenFactory.getInstance() returned null");
          }
      	
          //The userid and password can be obtained however you want
      
          // (Optional) Obtain the username and password configured in the callback handler
          Map wssContext = getWSSContext(_handler);            
          CallbackHandlerConfig chc = (CallbackHandlerConfig) wssContext.get(CallbackHandlerConfig.CONFIG_KEY);    
                                                           
          String username = chc.getUserId();                   
          char[] password = chc.getUserPassword();   
      
          UsernameToken unt = factory.getSimpleUsernameToken("myUsername", "myPassword".toCharArray());
      
          //Put the token in a list on the shared state where it will be available to be used by
          //stacked login modules
          factory.putGeneratorTokenToSharedState(_sharedState, unt);
      
          return true;
        }
        //implement the rest of the methods required by the
        //LoginModule interface
      }
  3. Create a JAAS login configuration.
    1. Note the full class name of the custom login module that you created in the previous step.
      For example, test.tokens.MyFullUntGenerator.
    2. Note the full class name of the login module that you are stacking on.
      For example, com.ibm.ws.wssecurity.wssapi.token.impl.UNTGenerateLoginModule or com.ibm.ws.wssecurity.wssapi.token.impl.GenericIssuedTokenGenerateLoginModule.
    3. In the administrative console, go to Security > Global security.
    4. Under Authentication, go to Java Authentication and Authorization Service > System logins.
    5. Click New, and under Alias, enter test.generate.unt.
    6. Under JAAS login modules, click New, and under Module class name, enter the name of your custom login module. Select Use login module proxy, and click OK.
    7. Click New, and under Module class name, enter the name of the login module that you are stacking on. Click OK.
  4. Configure the UsernameToken token generator to use the new JAAS login configuration.
    1. In the administrative console, open the bindings configuration that you want to change.
    2. Select WS-Security > Authentication and protection.
    3. Under Authentication tokens, select the outbound UsernameToken that you want to change.
    4. Under JAAS login, select test.generate.unt.
    5. Optional: If using GenericIssuedTokenGenerateLoginModule, add the passThroughToken=true custom property.
      1. Click Callback handler.
      2. Add the passThroughToken=true custom property.
      3. Click OK.
  5. Click Save.
  6. Restart the application server to apply the JAAS configuration changes.
  7. Test the service.