Web Services Authentication with Axis 2

by Ulf Dittmer

Last year I wrote an article on Web Services authentication. At the time Axis 1.x was used for the examples, but by now Axis 2 has been released, and I want to talk about the changes that this new version brings about. The first article is referenced repeatedly, so you may want to skim it at least before proceeding with this one.

An important improvement in Axis 2 is that WS-Security is now more tightly integrated with it. It used to be that the WSS4J library (which implements WS-Security) was a separate project, and needed to be added manually to an Axis installation, but no more. An Axis module called Rampart wraps the WSS4J functionality, and can be added to a base Axis installation with little effort.

Because WS-Security is so readily available now, it should be the preferred method of authentication. HTTP authentication as described in the first article can still be used (since Axis is implemented as a servlet in a web app), but it should be considered obsolete and be phased out. I will not discuss it here. Nor will I address the Tomcat Realm integration, because nothing has changed in that regard.

I will present two kinds of WS clients, one using the SAAJ API which was also discussed in the first article, the other one using Axis own API. Axis 2 no longer supports JAX-RPC, so that client is missing here (JAX-RPC is being replaced by JAX-WS, but that's not yet supported by Axis).

Preparation

A couple of steps need to taken before we can experiment with authentication.

The example files discussed in this article can be downloaded here: axis2-auth.zip

Axis 2 needs to be installed and 'happy'; this can be checked on the Axis installation home page (http://localhost:8080/axis2/) under the Validate link. Also, the AXIS2_HOME environment variable needs to set to the directory where the Axis distribution is installed.

Next, the WS-Security module Rampart needs to be installed. For this, copy the rampart-1.1.mar and addressing-1.1.mar files that are part of the example download to the WEB-INF/modules directory and restart the Axis web app. Now Rampart should be listed on the Axis Admin page (http://localhost:8080/axis2/axis2-admin/, default username is 'admin' with password 'axis2') under Available Modules.

Finally, the example web service must be installed. Copy the FibonacciService.aar file into the WEB-INF/services directory and once more restart Axis. FibonaciService should now be listed under Available Services, and it should report that rampart-1.1 is an engaged module for it. (Alternatively, the service archive file can also be uploaded through the Upload Service link on the Admin web page.)

Example

Now we're ready to play. Open a command prompt in the directory containing the examples, and start the tcpmon application by typing ant tcpmon. This will show the SOAP requests and responses in a convenient way.

Then run the SAAJ client by typing ant test-saaj -Dn=15 -Dport=8079. The 'n' parameter is the input to the Fibonacci function. You can choose a different one, but then the result will not be 610. The port 8079 is the one used by the tcpmon tool; use 8080 if you want to go straight to the Axis web app, thus not monitoring the call. (Note that the SAAJ client also logs the request and response to the console; I've not found a way to turn that off.)

All the interesting WS-Security information is in the wsse:Security element that's part of the SOAP header. It can have several child elements; in this case, wsu:Timestamp and wsse:UsernameToken are present. Why these, and what do they mean? WS-Security can perform 4 different actions: Timestamping, Authentication, Encryption and Signature. Here, the first two are used. A timestamp is used to indicate how long the supplied credentials (here: the username/password) are valid, and the service is supposed to reject them if it thinks that they are too old. Since we're focusing on the authentication, I'll not address timestamps in any more detail. They're optional in any case.

The username token essentially consists of the username and the password, which is digested in this case (meaning it can't be recovered should the message be intercepted).

The actual body is rather short, carrying the calculateFibonacci call with parameter 15. The response carries no WS-security information, just the calculateFibonacciResponse with result 610.

<?xml version='1.0' encoding='UTF-8'>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
        <wsse:Security
            xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/
                    oasis-200401-wss-wssecurity-secext-1.0.xsd"
            soapenv:mustUnderstand="1">

            <wsu:Timestamp
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
                        oasis-200401-wss-wssecurity-utility-1.0.xsd"
                wsu:Id="Timestamp-6557466">

                <wsu:Created>2007-04-30T18:29:15.687Z</wsu:Created>
                <wsu:Expires>2007-04-30T18:34:15.687Z</wsu:Expires>
            </wsu:Timestamp>

            <wsse:UsernameToken
                xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
                        oasis-200401-wss-wssecurity-utility-1.0.xsd"
                wsu:Id="UsernameToken-4055741">

                <wsse:Username>wsuser</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/
                        oasis-200401-wss-username-token-profile-1.0#PasswordDigest">
                    YaVaSHBtqjGDWoHEdB1zuB3CR68=</wsse:Password>

                <wsse:Nonce>E62qDYhYVoUkJSukJGrvdA==</wsse:Nonce>
                <wsu:Created>2007-04-30T18:29:15.665Z</wsu:Created>
            </wsse:UsernameToken>
        </wsse:Security>
    </soapenv:Header>

    <soapenv:Body>
        <ns1:calculateFibonacci xmlns:ns1="http://fibonacci/xsd">
            <in0>15</in0>
        </ns1:calculateFibonacci>
    </soapenv:Body>
</soapenv:Envelope>


<?xml version='1.0' encoding='UTF-8'>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>

    <soapenv:Body>
        <ns:calculateFibonacciResponse xmlns:ns="http://fibonacci/xsd">
            <ns:return>610</ns:return>
        </ns:calculateFibonacciResponse>
    </soapenv:Body>

The WS-Security options are controlled by the OutflowSecurity element the client config file conf/axis2.xml. The relevant section is this:

<parameter name="OutflowSecurity">
    <action>
        <items>UsernameToken Timestamp</items>

        <user>wsuser</user>

        <passwordCallbackClass>
            fibonacci.PWHandlerClient
        </passwordCallbackClass>

        <!--
        <passwordType>PasswordText</passwordType>
        -->

        <!--
        <timeToLive>10</timeToLive>
        -->
    </action>
</parameter>

It specifies that a UsernameToken and a Timestamp should be generated (the Timestamp being optional, as stated above). Furthermore, it tells Axis which username to use, and which class will supply the password that goes along with this username. Other options (commented out here) include the use of a cleartext password (instead of the digested one that is created by default), and how to specify a longer time-to-live for the timestamp (10 seconds instead of the default 5). The remainder of the file contains the non-WS-Security setup of Axis.

In addition to the conf/axis.xml file, both the Addressing and Rampart Axis module need to be available on the client side. The two APIs differ slightly in how to tell the application where to find these. For the SAAJ client, two system properties (axis2.repo and axis2.xml) must be set, while for the Axis API, these can be set programmatically (and thus are passed in via command line parameters). The build.xml file shows how to do that for both.

The server side config file (resources/META-INF/services.xml) has a similar section that specifies which WS-Security actions to perform, and which class to call to check the password:

<parameter name="InflowSecurity">
    <action>
        <items>UsernameToken Timestamp</items>

        <passwordCallbackClass>
            fibonacci.PWHandlerServer
        </passwordCallbackClass>
    </action>
</parameter>

The Axis API client produces the same request and response; it is run via ant test-axis2 -Dn=15 -Dport=8079.

Files in the examples download

axis2.log - log file written by the Axis client classes

build
    classes - where the compiled Java classes are kept
    FibonacciService.aar - service archive for deployment, created by ant generate.service
    FibonacciService.wsdl - WSDL description of the service, created by ant generate.wsdl

build.xml - Ant build file

conf
    axis2.xml - client side deployment descriptor

log4j.properties - log4j config file

modules
    addressing-1.1.mar - Axis module that implements WS-Addressing
    rampart-1.1.mar - Axis module that implements WS-Security

    (These versions are appropriate for Axis2 1.1; if you're using a different version,
    you should download its associated module files from the Axis2 web site.)

resources
    META-INF
        services.xml - server side deployment descriptor, goes into FibonacciService.aar

src
    fibonacci
        Axis2Client.java - WS client using the Axis API
        FibonacciService.java - the class implementing the service
        PWHandlerClient.java - handles passwords on the client
        PWHandlerServer.java - handles passwords on the server
        SAAJClient.java - WS client using the SAAJ API. It has a commented-out
            section that shows how to set and use arbitrary SOAP headers.

tcpmon.jar - standalone Swing app that can act as a proxy for web service
    requests and responses, and shows those in a structured way