WAS v8.5 > Develop applications > Develop web services - Security (WS-Security) > Develop applications that use Web Services Security > Develop message-level security for JAX-WS web services > Use Web Services Security SPIs

Generate and Consuming custom tokens with the Generic Issue Login Modules

The Generic Issued token generator and consumer, GenericIssuedTokenGenerateLoginModule, and GenericIssuedTokenConsumeLoginModule, can be used in conjunction with the GenericSecurityTokenFactory and GenericSecurityToken SPIs to implement an end-to-end solution for a custom token. Generating and consuming custom tokens with the Generic Issue Login Modules can be done with either policy and bindings, or WSSAPIs.

You must have a functioning set of JAX-WS service client and provider applications to which we can add new JAAS login module classes. Complete the following steps to enable a set JAX-WS service client and provider applications to use a custom token. Within these steps MyToken as the name of the token being created.

As you complete this task:

  1. Two JAAS login modules are created; one to generate the token, and one to consume it.
  2. The token is generated and consumed with the assistance of the Generic Issued token consumer and generator.
  3. The security constraints are then applied to the applications with policy sets and bindings.

  1. Create the following generator JAAS login module and make it available to the application code
    package test.tokens;
    
    import java.util.ArrayList;
    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 javax.xml.soap.SOAPFactory;
    import javax.xml.soap.SOAPElement;
    import javax.xml.namespace.QName;
    import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
    import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
    
    public class MyCustomGenerator 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 {
    
        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");
        }
        SecurityToken myToken = null;
        try {
          SOAPElement tokenElement = createCustomElement(factory);
          myToken = factory.getToken(tokenElement, new QName("http://www.acme.com","MyToken"));
        } catch (Exception e) {
          throw new LoginException(e.toString());
        }
        if (myToken == null) {
          throw new LoginException("myToken is null");
        }
    
        //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, myToken);
    
        return true;
      }
    
      private SOAPElement createCustomElement(GenericSecurityTokenFactory gstFactory) throws Exception {
        /*
          <acme:MyToken xmlns:acme="http://www.acme.com" 
                xmlns:utl="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" utl:Id="cust_3">         <acme:EMail>joe.smith@acme.com</acme:EMail>       </acme:MyToken>     */
        SOAPFactory factory = SOAPFactory.newInstance();
    
        //Create the MyToken element     SOAPElement tokElement = factory.createElement("MyToken", "acme", "http://www.acme.com");
        //Add the Id attribute     tokElement.addAttribute(new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id", "utl"), gstFactory.createUniqueId());
    
        //Create the Email element     SOAPElement emailElement = factory.createElement("Email", "acme", "http://www.acme.com");
        emailElement.addTextNode("joe.smith@acme.com");
    
        //Add the EMail element to the MyToken
        tokElement.addChildElement(emailElement);
    
        return tokElement;
      }
    
      public boolean logout() throws LoginException {
        return false;
      } 
      public boolean abort() throws LoginException {
        return false;
      }
      public boolean commit() throws LoginException {
        return true;
      }}

  2. Create the following consumer JAAS login module and make it available to the application code
    package test.tokens;
    
    import java.util.Map;
    import javax.xml.namespace.QName;
    import org.apache.axiom.om.OMElement;
    import javax.security.auth.Subject;
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.login.LoginException;
    import javax.security.auth.spi.LoginModule;
    import com.ibm.websphere.wssecurity.callbackhandler.PropertyCallback;
    import com.ibm.websphere.wssecurity.wssapi.token.GenericSecurityTokenFactory;
    import com.ibm.websphere.wssecurity.wssapi.token.SecurityToken;
    import com.ibm.wsspi.wssecurity.wssapi.OMStructure;
    
    public class MyCustomConsumer implements LoginModule {
    
      private CallbackHandler _handler;
      private Map _sharedState;
    
      public void initialize(Subject subject, CallbackHandler callbackHandler,
                             Map<String, ?> sharedState, Map<String, ?> options) {
        this._handler = callbackHandler;
        this._sharedState = sharedState;
      }
    
      public boolean login() throws LoginException {
        PropertyCallback propertyCallback = new PropertyCallback(null);
        Callback[] callbacks = new Callback[] { propertyCallback};
    
        try {
          this._handler.handle(callbacks);
        } catch (Exception e) {
          throw new LoginException(e.toString());
        }
        //Get the GenericSecurityTokenFactory
        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");
        }
        //Get the token that was consumed by the GenericIssuedConsumeLoginModule
        SecurityToken myToken = factory.getConsumerTokenFromSharedState(_sharedState, 
                                                                        new QName("http://www.acme.com","MyToken"));
    
        if (myToken == null) {
          throw new LoginException("no token");
        }
    
        //Get the token's element     Object obj = myToken.getXML();
        if (obj == null) {
          throw new LoginException("token is empty");
        }
        if (!(obj instanceof OMStructure)) {
          throw new LoginException("XML is not OMStructure");
        }
        OMElement tokenElement = ((OMStructure)obj).getNode();
        //we can use the org.apache.axis2.util.XMLUtils.toDOM method     //to work with the a w3c.dom element instead of an     //Axiom element 
        //Do some processing on the contents of the token element     OMElement el = tokenElement.getFirstChildWithName(new QName("http://www.acme.com","Email"));
        if (el == null) {
          throw new LoginException("no email element");
        }
        String value = el.getText();
    
        if (value != null && value.equals("joe.smith@acme.com")) {
          return true;
        } else {
          throw new LoginException("email value is bad");
        }
      }
      public boolean commit() throws LoginException {
        return true;
      }
      public boolean logout() throws LoginException {
        return false;
      }
      public boolean abort() throws LoginException {
        return false;
      }
    }

  3. Create new JAAS login configurations.

    1. In the dmgr console, select Security->Global security.

    2. Under Authentication, select Java Authentication and Authorization Service.

    3. Select System logins.

    4. Create the generator with the custom module first.

      1. Click New, and then specify Alias = test.generate.custom.

      2. Click New, and then specifyModule class name = test.tokens.MyCustomGenerator.

      3. Select Use login module proxy .

      4. Click OK.

      5. Click New, and then select Module class name = com.ibm.ws.wssecurity.wssapi.token.impl.GenericIssuedTokenGenerateLoginModule.

      6. Click OK.

      7. Click JAAS - System logins at the top of this console page.

    5. Create the consumer with the custom module last.

      1. Click New, and then specify Alias = test.consume.custom.

      2. Click New, and then select Module class name = com.ibm.ws.wssecurity.wssapi.token.impl.GenericIssuedTokenConsumeLoginModule.

      3. Click New, and then specify Module class name = test.tokens.MyCustomConsumer.

      4. Select Use login module proxy.

      5. Click OK .

    6. Click Save.

  4. Create the custom policy set.

    1. In the dmgr console, click Services > Policy sets > Application Policy sets.

    2. Click New, and then specify ACustomTokenPolicy.

    3. Click Apply.

    4. Under Policies, click Add > WS-Security.

  5. Edit the custom policy set.

    1. In the dmgr console, click WS-Security > Main Policy.
    2. Remove the unwanted elements:

      1. Unselect Include timestamp in security header.
      2. Unselect Message level protection.

    3. Add the custom token.

      1. Click Request token policies

      2. Click Add token type > Custom, and then specify:

        • Custom token name = myToken
        • Local part = MyToken
        • Namespace URI = http://www.acme.com

      3. Click OK.

    4. Click Save.

  6. Configure the client to use the ACustomTokenPolicy policy set.

    1. In the dmgr console, click Services > Service clients.

    2. Click on the desired service client.

    3. Select the resource at the top level.

    4. Click Attach Policy Set.

    5. Select ACustomTokenPolicy

  7. Create a custom binding for the client.

    1. Select the resource at the top level again.

    2. Click Assign Binding.

    3. Click New Application Specific Binding to create an application-specific binding.

    4. Specify the bindings configuration name.

      name: customTokenClientBinding

    5. Click Add > WS-Security.

      If the Main Message Security Policy Bindings panel does not display, select WS-Security.


  8. Configure the client's custom bindings.

    1. Select Authentication and protection > request:myToken.

    2. Select JAAS login = test.generate.custom.

    3. Click Apply.

    4. Click Callback handler.

    5. Add the passThroughToken=true custom property.

  9. Configure the provider to use the ACustomTokenPolicy policy set.

    1. In the dmgr console, click Services > Service providers.

    2. Click on the desired service provider.

    3. Select the resource at the top level.

    4. Click Attach Policy Set.

    5. Select ACustomTok enPolicy.

  10. Create a custom binding for the provider.

    1. Select the resource at the top level again.

    2. Click Assign Binding.

    3. Click New Application Specific Binding to create an application-specific binding.

    4. Specify the bindings configuration name.

      customTokenProviderBinding

    5. Click Add > WS-Security.

      If the Main Message Security Policy Bindings panel does not display, select WS-Security.

  11. Configure the custom bindings for the provider.

    1. Select Authentication and protection > request:myToken.

    2. Select JAAS login = test.consume.custom

    3. Click Apply.

    4. Click Callback handler.

    5. Add the passThroughToken=true and alwaysGeneric=true custom properties.

  12. Click Save to save your configuration changes.

  13. Restart the application server to apply the JAAS configuration changes.
  14. Test your service.


Example

The following example illustrates the SOAP Security header that is produced when we follow the preceding procedure.


Related


Create a SAML bearer token using the API
Create a SAML holder-of-key token using the API
Create a SAML sender-vouches token using the API


+

Search Tips   |   Advanced Search