Developing web services applications to use a UsernameToken with no registry interaction

To authenticate a UsernameToken with a caller part without accessing the WebSphere Application Server registry, you can replace the authentication method of the UsernameToken consumer and configure the caller to use an alternative Java™ Authentication and Authorization Service (JAAS) login configuration.

About this task

This information applies only to Java API for XML-based RPC (JAX-RPC) web services.

By default, the default JAAS login module that is used with the web Services Security UsernameToken consumer, UsernameLoginModule, always validates the user name and password that are contained within the token against the WebSphere registry. You can configure a custom property to circumvent this registry check. When a caller part is added to the WS-Security constraints for a service provider, the user name and password that are contained in the UsernameToken are also validated against the WebSphere registry. This validation occurs in the com.ibm.ws.security.server.lm.ltpaLoginModule module that is part of the system.DEFAULT Java Authentication and Authorization Service (JAAS)configuration stack, as shown in the following example.

com.ibm.ws.security.server.lm.ltpaLoginModule
com.ibm.ws.security.server.lm.wsMapDefaultInboundLoginModule

The WebSphere Application Server WS-Security run time does not support the use of a JAAS configuration for the caller part that does not include these two login modules. However, you can add your own custom login modules to this JAAS configuration stack.

To use a UsernameToken with a caller part without accessing the WebSphere Application Server registry, you must prevent both the UsernameLoginModule and ltpaLoginModule modules from accessing the registry.
Note: When a UsernameToken is added to a provider application using the wizard in an application developer, it automatically adds a caller part for the UsernameToken. A caller part is only needed if you want the identity from the UsernameToken to be on the thread of execution. If your application does not require the identity from the UsernameToken to be on the thread of execution, then you do not need the caller part and can remove it. The caller part is configured in the deployment descriptor extensions and can be accessed only with an application developer

Refer to the Configuring the caller in consumer security constraints topic in the IBM Rational Application Developer documentation.

Procedure

  1. To prevent the UsernameLoginModule module from accessing the registry, add the com.ibm.wsspi.wssecurity.auth.module.UsernameLoginModule.disableUserRegistryCheck custom property to the JAAS configuration for the UsernameToken consumer. You can add this custom property in one of two ways:
    Note: The update to the wssecurity.UsernameToken JAAS configuration causes all users of this JAAS configuration on the application server to not check the registry. If you do not want this behavior, create a new JAAS configuration or use the method to update the UsernameToken consumer

    To add the custom property to the com.ibm.wsspi.wssecurity.auth.module.UsernameLoginModule module in the wssecurity.UsernameToken JAAS configuration:

    1. Click Security > Global security.
    2. Under Authentication, click Java Authentication and Authorization Service > System logins.
    3. Select wssecurity.UsernameToken.
    4. Select com.ibm.wsspi.wssecurity.auth.module.UsernameLoginModule.
    5. Add the following custom property: com.ibm.wsspi.wssecurity.auth.module.UsernameLoginModule.disableUserRegistryCheck=true.
    6. Click OK.
    7. Restart the application server to reload the updated JAAS configuration.

    To add the custom property to the application's token consumer, perform the following steps:

    1. Click Applications > Application Types > WebSphere enterprise applications > (providerAppName) > Manage Modules > (moduleName) > Web services: Server security bindings.
    2. Under Request consumer (receiver) binding, click Edit custom > Token consumers.
    3. Select your UsernameToken consumer.
    4. Click JAAS configuration > Properties > New.
    5. Add the following custom property: com.ibm.wsspi.wssecurity.auth.module.UsernameLoginModule.disableUserRegistryCheck=true.
    6. Click OK.
    7. Click Save.
    8. Restart the application.
    Note: If your UsernameToken consumer's name looks like 'Token_123' and is not selectable, then the application developer that you used to add your security constraints failed to give a name to your token consumer in the deployment descriptor. As an alternative, you can perform one of the following two options.
    1. Add the property to the security JAAS configuration as described in step 1.
    2. Edit the deployment descriptor bindings in your application project using an application developer.
    Refer to the Configuring the security token requirement in consumer security constraints topic in the IBM Rational Application Developer documentation.
  2. Develop a JAAS login module that stacks above com.ibm.ws.security.server.lm.ltpaLoginModule. The following example shows sample code for the JAAS login module:
    package test.tokens;
    import java.util.Map;
    import java.util.Hashtable;
    
    import javax.security.auth.Subject;
    import javax.security.auth.login.LoginException;
    import javax.security.auth.spi.LoginModule;
    import javax.security.auth.callback.NameCallback;
    import javax.security.auth.callback.PasswordCallback;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import com.ibm.wsspi.wssecurity.auth.token.UsernameToken;
    import com.ibm.wsspi.security.token.AttributeNameConstants;
    
    public class MyAuthLoginModule implements LoginModule {
    
    	  private Map _sharedState = null;
    	  private CallbackHandler _callbackHandler = null;
    	  Subject _subject = null;
    
    
    	public void initialize(Subject subject, CallbackHandler callbackHandler,
                  Map<String, ?> sharedState, Map<String, ?> options) {
    	    this._sharedState = sharedState;  
    	    this._callbackHandler = callbackHandler;
    	    this._subject = subject;		
    	}
    
    	public boolean login() throws LoginException {
    	    //For the sake of readability, this login module does not
    	    //protect against all NPE's
    
    	    String username = null;
    	    char [] password = null;
    	    NameCallback nameCallback = null;
    	    PasswordCallback passwordCallback = null;
    
    	    //Get the username and password from callbacks that
    	    //the ws-security runtime set up
    	    Callback[] callbacks = new Callback[2];
    	    callbacks[0] = nameCallback = new NameCallback("Username: ");
    	    callbacks[1] = passwordCallback = new PasswordCallback("Password: ", false);
    	    try {
    	      _callbackHandler.handle(callbacks);
    	    } catch ( Exception e ) {
    	      throw new LoginException("Unable to process callbacks");
    	    }
    
    	    if (nameCallback != null) {
    	      username = nameCallback.getName();
    	    }
    
    	    if (passwordCallback != null) {
    	      char tmp[] = passwordCallback.getPassword();
    	      if (tmp != null && tmp.length != 0) {
    	        password = new char[tmp.length];
    	        System.arraycopy(tmp, 0, password, 0, tmp.length);
    	      }
    	    }
    
    	    if (username == null) {
    	      throw new LoginException("Unable to obtain username");
    	    }
    
    	    //If you will be validating the username and password,
    	    //validate it here
    
    	    Hashtable customProperties = (Hashtable)_sharedState.get(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY);
    	    if (customProperties == null) {
    	      customProperties = new Hashtable();
    	     _sharedState.put(AttributeNameConstants.WSCREDENTIAL_PROPERTIES_KEY, customProperties);
    	    }
    
    	   // Default realm is used here, but any trusted realm can be used
    	   String uid = "defaultWIMFileBasedRealm/" + username;
    	   customProperties.put(AttributeNameConstants.WSCREDENTIAL_UNIQUEID, uid)
    	   // SECURITYNAME will be the principal name
    	   customproperties.put(AttributeNameConstants.WSCREDENTIAL_SECURITYNAME, username);
    
    	    return true;
    	  }
    
    	public boolean logout() throws LoginException {
    		return false;
    	}
    
    }
  3. Create a JAAS login configuration.
    1. In the administrative console, select Security > Global security.
    2. Under Authentication, select Java Authentication and Authorization Service > System logins.
    3. Click New, and under Aliases, enter test.auth.jaxrpcunt.
    4. Add the JAAS login modules. You must add the following login modules in the order shown:
      test.tokens.MyAuthLoginModule
      Note: The name of this module must match the JAAS login module that you developed.
      com.ibm.ws.security.server.lm.ltpaLoginModule
      com.ibm.ws.security.server.lm.wsMapDefaultInboundLoginModule

      For each login module:

      1. Under JAAS login modules, click New.
      2. Under Module class name, enter the name of the login module.
      3. For test.tokens.MyAuthLoginModule only, select Use login module proxy.
      4. Click OK.
      5. Click OK, then Save.
  4. Restart the application server to apply the JAAS configuration changes.
  5. Configure your caller part to use the new JAAS configuration. You can configure your caller part by using only an application developer.
    Refer to the Configuring the caller in consumer security constraints topic in the IBM Rational Application Developer documentation.
    • Add the following custom property to the caller part for the UsernameToken: com.ibm.wsspi.wssecurity.Caller.assertionLoginConfig=system.test.auth.jaxrpcunt.
    • Save the deployment descriptor
    • Redeploy the application to the server
  6. Test the service.