+

Search Tips   |   Advanced Search

(WAS v8.5.0.1)

Generating 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.

We 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 is 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 console, select Security->Global security > Authentication, select Java Authentication and Authorization Service.

    2. Select System logins.

    3. 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.

    4. 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 .

    5. Click Save.

  4. Create the custom policy set.

    1. In the 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 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 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 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 the configuration changes.

  13. Restart the application server to apply the JAAS configuration changes.

  14. Test the service.


Example

Example SOAP Security header that is produced when you follow the preceding procedure.

<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
    <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>
</wsse:Security>


Related tasks

  • Create custom security tokens for Web services security using the GenericSecurityTokenFactory SPIs
  • Generating a dynamic UsernameToken using a stacked JAAS login module