Axis1 Deployment Tutorial

WSS4J 1.5.x Axis handlers process SOAP requests according to the OASIS Web Service Security (WSS) specifications.

The WSS4J Axis handlers WSDoAllSender and WSDoAllReceiver control the creation and consumption of secure SOAP requests. The handlers work behind the scenes and are usually transparent to Web Service (WS) applications. The Axis deployment descriptor files (*.wsdd) may contain all necessary information to control the security processing.

A WS application may also set properties to control the handlers and provide default values. If the deployment descriptor sets the same property (parameter) then the deployment descriptor overwrites the application defined property. Thus, deployment settings overwrite application settings to fulfill site specific requirements.

Prerequisites

The WS Security Axis handlers use the WSS4J classes (Web Service Security for Java) to process the SOAP messages. WSS4J in turn uses the Apache XML Security project to handle XML Security according to XML Signature and XML Encryption.

The WSS4J Axis handlers require Axis V1.2 because of some problems in previous Axis versions. WSS4J CVS contains the latest Axis libraries.

Related Documentation

The OASIS WSS specifications define a number of features and it is possible to combine them in several ways. The WSS4J Axis handlers already support a large number of WSS features and their combinations. Here are the WSS specifications.

The basics - a simple example that uses

This chapter gives an overview and some examples how to deploy the WSS4J Axis handlers and how the parameters and their values control the handlers. For a better understanding of this chapter the reader shall have a knowledge of the OASIS WSS specifications.

The {@link org.apache.ws.security.handler.WSHandlerConstants}, {@link org.apache.ws.axis.security.WSDoAllSender}, and {@link org.apache.ws.axis.security.WSDoAllReceiver} provide additional and detailed documentation.

Axis deployment descriptor to insert a

The following snippet shows a general layout how to deploy a WS Axis handler on the client (application) side.

 <!-- define the service, use the WSDoAllSender security handler in request flow -->
 <service name="Ping1">
  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
    <parameter name="action" value="UsernameToken"/>
    <parameter name="user" value="werner"/>
    <parameter name="passwordType" value="PasswordText" />
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback1Out"/>
   </handler>
  </requestFlow>
  </service>
This is the standard way to deploy an Axis handler. Axis parses the deployment descriptor and provides the parameters and their value to the handler. Each service can have its own request and response flow definition, which provides a very flexible set-up of the security parameters.

The above setup inserts the most simple security structure into a SOAP request: the simple UsernameToken. This token includes a username and the according password. Both fields are sent in cleartext, thus it provides no real security.

The parameters and their meanings are:

  • action defines the security action. The value UsernameToken directs the handler to insert this token into the SOAP request.
  • user specifies the username to include in the token.
  • passwordType is a pecific parameter for the UsernameToken action and defines the encoding of the passowrd. PasswordText specifies to send the password in plain text, PasswordDigest specifies to send the password in digest mode (refer to WSS UsernameToken Profile)
  • passwordCallbackClass contains the name of a class that implements a method to get the user's password. Please refer to the detailed documentation in {@link org.apache.ws.security.handler.WSHandlerConstants#PW_CALLBACK_CLASS}.
The WSS4J Axis security handler interprets the parameter values and controls the WSS4J modules to generate the following SOAP request:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext" 
      soapenv:mustUnderstand="true">
      <wsse:UsernameToken>
        <wsse:Username>werner</wsse:Username>
        <wsse:Password Type="wsse:PasswordText">security</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <Ping xmlns="http://xmlsoap.org/Ping">
      <text>Scenario 1 text</text>
      <ticket xmlns:ns1="http://xmlsoap.org/Ping" 
        xsi:type="ns1:ticketType">scenario1</ticket>
    </Ping>
  </soapenv:Body>
</soapenv:Envelope>
This is a pretty print of the real SOAP message.

The password callback class

The deployment descriptor contains the user name that the handler inserts into the UsernameToken but not the password. In general it is not a good idea to store sensitive information like a password in cleartext. To get the password the WSS4J Axis handler uses a password callback technique similar to the JAAS mechansim. The parameter passwordCallbackClass contains the classname of the callback class. This class must implement the {@link javax.security.auth.callback.CallbackHandler} interface. The WSS4J Axis handler gets this class, instantiates it, and calls the handle method when it needs a password. Refer also to the {@link org.apache.ws.security.handler.WSHandlerConstants#PW_CALLBACK_CLASS parameter} documentation.

The following code snippet shows a simple password callback class:

package org.apache.ws.axis.oasis;

import java.io.IOException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class PWCallback implements CallbackHandler {

  private static final byte[] key = {
    (byte)0x31, (byte)0xfd, (byte)0xcb, (byte)0xda,
    (byte)0xfb, (byte)0xcd, (byte)0x6b, (byte)0xa8,
    (byte)0xe6, (byte)0x19, (byte)0xa7, (byte)0xbf,
    (byte)0x51, (byte)0xf7, (byte)0xc7, (byte)0x3e,
    (byte)0x80, (byte)0xae, (byte)0x98, (byte)0x51,
    (byte)0xc8, (byte)0x51, (byte)0x34, (byte)0x04,
  };
	
  public void handle(Callback[] callbacks)
    throws IOException, UnsupportedCallbackException {
    for (int i = 0; i < callbacks.length; i++) {
      if (callbacks[i] instanceof WSPasswordCallback) {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
        /*
         * here call a function/method to lookup the password for
         * the given identifier (e.g. a user name or keystore alias)
         * e.g.: pc.setPassword(passStore.getPassword(pc.getIdentfifier))
         * for testing we supply a fixed name/fixed key here.
         */
        if (pc.getUsage() == WSPasswordCallback.KEY_NAME) {
          pc.setKey(key);
        }
        else {
          pc.setPassword("security");
        }
      } else {
        throw new UnsupportedCallbackException(
          callbacks[i], "Unrecognized Callback");
      }
    }
  }
}
The Java {@link javax.security.auth.callback.CallbackHandler callback} handler documentation provides a detailed description of the interface and exceptions.

The WSS4J library uses a specific class to get the required password or key informations. The WSSPasswordCallback class implements the {@link javax.security.auth.callback.Callback} interface according to the JAAS. Depending on it usage this class either carries the required password as a Java String or it carries the required key information as a Java byte[] array. Refer to {@link org.apache.ws.security.WSPasswordCallback} that contains a detailed description of the usage codes.

The WSS4J Axis handler or the WSS4J modules set the usage code before they call handle method.

Application sets parameters to insert in

Sometimes it is not feasable or not possible to determine parameters and their values during deployment. In this case the application can set paramters during runtime. The WSS4J Axis handlers use the Axis setProperty method to support this feature.

The following code snippet shows an example how to use the dynamic setting of parameters and their values:

   ...
 Service service = new Service();
 Call call = (Call) service.createCall();
   ...  
 call.setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
 call.setProperty(WSHandlerConstants.USER, "werner");
   ...
Use this way if your application dynamically creates a call object. If your application uses stubs generated by Axis' WSDL2Java tool, the application uses the following functions:
    ...
 PingServiceLocator service = new PingServiceLocator();
    ...
 PingPort port = (PingPort) service.getPing1();
 port._setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
 port._setProperty(WSHandlerConstants.USER, "werner");
    ...
Please note that _setProperty is a Axis specific call.

The password callback object reference

In addition to the password callback class an application may set a password callback object using the setProperty() methods. Only applications (and Axis handlers that preceed the WSS4J Axis handlers in a handler chain) can use this feature.

For example:

public class Scenario1 implements CallbackHandler {

  public static void main(String args[]) {
    ...
    PingServiceLocator service = new PingServiceLocator();
    ...
    PingPort port = (PingPort) service.getPing1();
    ((org.apache.axis.client.Stub)port)._setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PASSWORD_TEXT);
    ((org.apache.axis.client.Stub)port._setProperty(WSHandlerConstants.USER, "werner");
    ((org.apache.axis.client.Stub)port._setProperty(WSHandlerConstants.PW_CALLBACK_REF, this);
    ...
  }

  public void handle(Callback[] callbacks) {
    ...
  }
}

Deployment of the WSS4J Axis handler

Similar to the deployment descriptor of the sending handler WSDoAllSender a deployment descriptor for the receiving handler exists. For the above example the deployment descriptor look like:

  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="action" value="UsernameToken"/>
   </handler>
  </requestFlow>
The receiving WSS4J Axis handler checks if the SOAP request matches the defined actions.

Combining security actions

Often it is necessary to combine or concatenate several security actions, for example to encrypt parts of a message and sign some other parts. The WSS4J Axis handlers provide easy and simple methods to combine or concatenate security actions.

This chapter describes simple combinations of actions.

Combine and

The WS Interoperability specifications define this use case:

  • Insert a UsernameToken, use PasswordText to set the password. In addition add a timestamp and a nonce into the UsernameToken
  • Encrypt the UsernameToken to protect the information.
The Axis deplyment descriptor for this use case:
  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
    <parameter name="action" value="UsernameToken Encrypt"/>
    <parameter name="user" value="werner"/>
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="passwordType" value="PasswordText" />
    <parameter name="addUTElement" value="Nonce Created" />
    <parameter name="encryptionPropFile" value="crypto.properties" />
    <parameter name="encryptionKeyIdentifier" value="X509KeyIdentifier" />
    <parameter name="encryptionUser" 
      value="16c73ab6-b892-458f-abf5-2f875f74882e" />
    <parameter name="encryptionParts" 
      value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}UsernameToken" />  
   </handler>
  </requestFlow>  
This descriptor contains some new parameters to control the UsernameToken element and its encryption. The new parameters and their meaning are:
  • addUTElement - controls if the handler shall insert elements into the UsernameToken. The value is a blank separated list of element names to include. Only Nonce and Created are supported.
  • encryptionPropFile - the name of a crypto property file. This file contains parameters and property that control the encryption. Please refer to the {@link org.apache.ws.security.handler.WSHandlerConstants#ENC_PROP_FILE detailed} description of the cyrpto property file.
  • encryptionKeyIdentifier - specifies the format in which the handler inserts the encryption key into the SOAP request. Please refer to the {@link org.apache.ws.security.handler.WSHandlerConstants#ENC_KEY_ID detailed} description.
  • encryptionUser - the name or identifier of the user who owns the public key to encrypt the data. Usually this is the name or alias name of the owner's certificate in a keystore.
  • encryptionParts - controls which part or parts the handler of the SOAP shall encrypt. If this parameter is not defined, WSS4J encrypts the whole SOAP Body in Content mode. The value of the parameter in this example specifies to encrypt the element UsernameToken, contained in the namespace http://schemas.xmlsoap.org/ws/2002/07/secext. The encryption module uses the Element mode to encrypt the element data. Please refer to the {@link org.apache.ws.security.handler.WSHandlerConstants#ENCRYPTION_PARTS detailed} description.
The matching receiver deployment descriptor:
  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="action" value="UsernameToken Encrypt"/>
    <parameter name="decryptionPropFile" value="crypto.properties" />
   </handler>
  </requestFlow>
The only new parameter here is the decryptionPropFile. This parameter defines the crypto property file at the receiver side. The value of the action parameter matches the according value at the sender side. The WSS4J Axis receiver checks if the SOAP request contains the required security data.

Combine Signature and Encryption

This is a very common usage of Web Service security. The WSS4J Axis handler provides flexible parameter settings that support several ways to use the Signature/Encryption combination.

A WSS4J Axis deployment descriptor for a simple Singature/Encryption of SOAP requests:

<requestFlow>
  <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
    <parameter name="user" value="16c73ab6-b892-458f-abf5-2f875f74882e"/>
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="action" value="Signature Encrypt"/>
    <parameter name="signaturePropFile" value="crypto.properties" />
  </handler>
</requestFlow>
This simple deployment descriptor signs and encrypts the SOAP Body part. The only new parameter, signaturePropFile, specifies the name of the signature crypto property file to use. Because no encryptionPropFile is declared the handler also uses the signature property file to get the encryption certificate. The same holds true for the username. The password callback class must return a password to get the user's private key (the keystore is defined in the crypto property file) that WSS4J uses to generate the signature. The encryption method uses the user's public key to encrypt the dynamically generated session key.

The action parameter defines Signature Encryption. Thus the handler first signs, then the encrypts the data. Because the deployment descriptor does not contain specific encryption or signature part parameters, WSS4J defaults to the data of the SOAP Body element.

Also all other parameters use their default setting, such as the format of the key identifiers, encryption modifiers, and so on. Please refer to the {@link org.apache.ws.security.handler.WSHandlerConstants detailed} documentation of the parameters.

If the WSS4J Axis handler shall perform encryption only, then the deployment descriptor must contain the encryption specific parameters. Only if sign and encryption is required the encryption method falls back to the signature parameters if the encryption specific parameters are not set.

The matching receiver deployment descriptor is also very simple:

<requestFlow>
  <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="action" value="Signature Encrypt"/>
    <parameter name="signaturePropFile" value="crypto.properties" />
  </handler>
 </requestFlow>	
To reverse the actions, just reverse the action specifiers. The WSS4J handler encrypts the SOAP Body first, then signs the encrypted data.

Signing and encrypting multiple XML elements

Sometimes it is necessary to sign and/or encrypt several parts of a SOAP message. The deployment parameters signatureParts and encryptionParts control which SOAP elements to sign or to encrypt. Please refer to the {@link org.apache.ws.security.handler.WSHandlerConstants#ENCRYPTION_PARTS detailed} description of these parameters.

WSS4J signs or encrypts all declared parts using the same keys, that is the signature or encryption data structures directly reference the specified parts as described in the WSS specifications. The receiver automatically detects these references and verfies and decrypts the data parts. No special settings in the depolyment descriptor is necessary.

Chaining of WSS4J Axis handlers

This is a very powerful feature that supports even more flexible signature and encryption processing such as signatures with multiple keys (overlapping signatures), multiple encryption algorithms, or different SOAP actor (role) defintions of the security headers.

Deployment at the client

A deployment descriptor to chain handlers:

  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
    <parameter name="action" value="Signature NoSerialization"/>
    <parameter name="user" value="firstUser"/>
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="signaturePropFile" value="crypto.properties" />
    <parameter name="signatureParts" value="{}{http://xmlsoap.org/Ping}ticket" />    
   </handler>
   <handler type="java:org.apache.ws.axis.security.WSDoAllSender" >
    <parameter name="action" value="Signature"/>
    <parameter name="user" value="anotherUser"/>
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="signaturePropFile" value="crypto.properties" />
   </handler>  
  </requestFlow>
Note the action specifier NoSerialization first handler. In a handler chain of WSS4J handlers every but the last handler must have this action specifier. This specifier surpresses the very last step of the handler's security processing: the serialization of the processed SOAP request in a XML string (document) that Axis sends to the reveiver. Only the last handler must perform this serialization.

Every handler specification can have its own set of parameters that define the individual values for this handler instance. Thus the deployment descriptor can define different crypto property files, different usernames, and so on. In the example the first handler signs the ticket element and the second handler the SOAP Body (default).

Parameters set by the application with setProperty are valid for all handler instances in the handler chain (setProperty is defined on the SOAP request (call) level). As already decribed, deployment settings overrule application settings. Thus it is possible to combine various parameter specifications. A special case is the definition of the username. If an application sets the username and one handler instance in the chain does not have a user parameter in its deployment part, then this one handler instance uses the username set bey the application. After the handler copied the username from the username property, the handler sets the property's content to null. Handlers that follow in the chain cannot use this username anymore and must have a user (or encryption user) parameter in their deployment part.

Deployment at the server

Note: Handler chaining at the receiver side is not yet fully tested.

Handlers at the receiver can only determine different security headers if their SOAP actors are different. The WSS4J handler processes each security structure inside one security header. Because the security structures contain most information to verify or decrypt the SOAP request this constraint is not too much of an issue.

Only the password call back class and the Crypto implementation (as defined in the crypto property file) must be able to handle all possible certificates, users, passwords, and keys that a security header may contain. The following deployment descriptor of a receiver shows this.

  <requestFlow>
   <handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
    <parameter name="passwordCallbackClass" 
      value="org.apache.ws.axis.oasis.PWCallback"/>
    <parameter name="action" value="Signature Signature"/>
    <parameter name="signaturePropFile" value="crypto.properties" />
   </handler>
  </requestFlow>
The client uses two handlers in a chain, each signing a part of the SOAP request but with different certificates. Because the handlers do not specifiy a SOAP actor WSS4J puts both signatures in the security header of the default actor. To match the security actions the deployment descriptor of the receiver needs to contain the action declaration Signature Signature. This instructs the WSS4J handler to accept and verify two distinct signatures contained in one security header. Because the signatures use different certificates the Crypto implementation must be able to handle these certificates.

Similar requirements are true for the password callback implementation if the sender uses handler chaining and uses different encryption parameters in the same security header.

If it is necessary to have different parameters for the distinct signature or decryption data then these should be put in different security headers. The easiest way to do this is to define different actor parameters for each handler in a WSS4J handler chain.

Reporting Security results to services/applications

The WSS4J WSSecurityEngine processes the security elements inside a security header. If something goes wrong, for example a signature verfication fails, then the engine throws a fault. If the security engine could perform all operations sucessfully it returns a data structure that contains the results of the performed security actions. This data structure holds information about the performed action, the usernames or identifier in case the security engine performed signature or username token processing. Please refer to the {@link org.apache.ws.security.WSSecurityEngineResult result} structure.

The WSDoAllReceiver WSS4J handler takes this structure and checks if all required actions were performed. If this check fails, the WSS4J handler aborts the SOAP request and throws an Axis SOAP fault. Otherwise it creates its own data structure {@link org.apache.ws.axis.security.WSDoAllReceiverResult}, copies the security results in this structure, and adds the actor name of the security header. The it stores this new data structure in a vector and stores this vector in a specific {@link org.apache.ws.security.handler.WSHandlerConstants#RECV_RESULTS property} of the current message context. If WSS4J handlers are chained, then every handler in the chain adds its result to the vector. The vector contains the results in handler-chain order.

This code snippet shows how a Axis service can access the security result data:

    public void ping(javax.xml.rpc.holders.StringHolder text,
        org.apache.ws.axis.oasis.ping.TicketType ticket)
        throws java.rmi.RemoteException {

        text.value = "Echo " + text.value.trim();
		
        // get the message context first
        MessageContext msgContext = MessageContext.getCurrentContext();
        Message reqMsg = msgContext.getRequestMessage();

        Vector results = null;
        // get the result Vector from the property
        if ((results =
            (Vector) msgContext.getProperty(WSHandlerConstants.RECV_RESULTS))
             == null) {
            System.out.println("No security results!!");
        }
        System.out.println("Number of results: " + results.size());
        for (int i = 0; i < results.size(); i++) {
            WSHandlerResult hResult = (WSHandlerResult)results.get(i);
            String actor = hResult.getActor();
            Vector hResults = hResult.getResults();
            for (int j = 0; j < hResults.size(); j++) {
              	WSSecurityEngineResult eResult = (WSSecurityEngineResult) hResults.get(j);
                // Note: an encryption action does not have an associated principal
    	        // only Signature and UsernameToken actions return a principal
                if (eResult.getAction() != WSConstants.ENCR) {
                    System.out.println(eResult.getPrincipal().getName());
                }
            }
        }
    }
The principal structure is either a {@link org.apache.ws.security.WSUsernameTokenPrincipal UsernameToken} principal or a {@link java.security.Principal X509Principal}. The princpals contain the names plus other information of the verified username token or signature certificate.

Some hints

Client

At the client side, the WSS4J Axis handler, as all other parts of Axis, run in the context of the calling application. Depending on the application, the callback classes may perform complex operations, even do some user interaction, to get the password or to access some database to get certificates or keys. There are no timeouts defined at the client side before the SOAP request is put on the wire.

Server

On the server side the WSS4J handler run in the same context as the other part of the server, usually some servlet container, such as Tomcat. Also the server must be able to handle many requests in a short time. Thus the password callback as well as the Crypto implementation shall be as fast as possible. In general, no user interaction is possible at the server side to gather passwords. Also at this point of the SOAP request processing there are active timeouts, even if they are fairly long.

Bi-directional SOAP Security

WSS4J fully supports bi-directional SOAP security. To enable bi-directional support just put WSDoAllSender on the responseFlow at the server and WSDoAllReceiver at the response flow of the client thus reversing the roles. Similar to the above hints, the server side part (now WSDoAllSender) runs in the server context and WSDoAllReceiver runs in the application (client) context. There are no Axis timeout constraints on the client side after Axis received the response and handed it over to the WSS4J handler.

Handler chaining

Usually WSS4J handlers are chained without any other handler between them in the chain. It is, however, possible to do so. In this case the intermediate handler must not modify the SOAP Envelope that is contained in the Axis message. This could (most probably will) invalidate or destroy any security actions done sofar. Such an intermediate handler may set some properties that may influence the processing of the following WSS4J handler, such as setting a new username, password callback class, and so on. @since WSS4J 1.0