Understanding web services specifications, Part 4: WS-Security

There are few (if any) enterprise-level systems that don't require one form of security or another. In web services, this process is more complicated than in other arenas because of the distributed, stateless nature of the beast. This tutorial, Part 4 of the Understanding web services specifications series, explains the concepts behind WS-Security and related standards such as XML Signature, which combine to make security in the web services world not just possible, but practical.

Share:

Nicholas Chase (ibmquestions@nicholaschase.com), Freelance writer, Backstop Media

Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sam's).



22 August 2006

Also available in Chinese Vietnamese Portuguese Spanish

Before you start

In this tutorial you'll learn about Web Services Security, or WS-Security. It is for developers who wish to expose their own services in an environment that requires protection of messages from being tampered or read in transit, or in situations in which the sender must be positively identified. The term "WS-Security" is usually used to refer to a group of specifications that handle encryption and digital signatures, enabling you to create a secure application.

In order to follow along with this tutorial, you should have a basic understanding of SOAP, which you can achieve by reading Part 1 of this tutorial series, and by extension, you need a basic understanding of XML. SOAP is programming-language agnostic, but the samples in this tutorial use Java ™ and the Apache Axis2 project. The concepts, however, apply to any programming language and environment.

About this series

This tutorial series teaches the basic concepts of web services by following the exploits of the fictional newspaper, The Daily Moon, as the staff uses web services to create a workflow system to increase productivity in the midst of much change.

Part 1 explained the basic concepts behind web services and showed how to use SOAP, the specification that underlies most of what is to come, connecting the classifieds department with the Content Management System.

Part 2 takes things a step further, explaining how to use Web Services Description Language (WSDL) to define the messages produced at expected by web service, enabling the team to more easily create services and the clients that connect to them.

Part 3 finds the team with a number of services in place and a desire to locate them easily. In response, Universal Description, Discovery and Integration (UDDI) provides a searchable registry of available services at a way to publicize their own services to others.

Now in Part 4, Rudy, publisher of the The Daily Moon, has decided that the paper needs to institute better security procedures for web services that access their internal systems.

In Part 5, WS-Policy, we will look at the changes the teams need to make in order to access those newly secured services.

Interoperability will be the key word in Part 6, as services from several different implementations must be accessed from a single system. Part 6 will also cover the requirements and tests involved in WS-I certification.

Finally, Part 7 will show how to use Business Process Execution Language (WS-BPEL) to create complex applications from individual services.

Now let's look at what this tutorial covers in a bit more detail.

About this tutorial

In this tutorial, you will follow along as the The Daily Moon newspaper team uses the WS-Security specifications to secure one of the web services described thus far in the series.

In the course of this tutorial, you will learn:

  • What WS-Security is
  • The difference between symmetric and asymmetric encryption
  • The difference between signatures and encryption
  • The effect of security on SOAP messages
  • How to secure a SOAP web service using Axis2

Before we get started, you'll need a few tools.

Prerequisites

Much of this tutorial is conceptual, but in order to follow along with the code that creates the SOAP messages, you will need to have the following software available and installed:

We will demonstrate the installation and use of Apache Geronimo, which is also the basis for IBM's WebSphere Community Edition. You can also use other application servers such as WebSphere application server. You can download Apache Geronimo. For more information on installing Geronimo, see Part 1 of this tutorial series.

You will be using Apache Axis2, which contains implementations of various SOAP-related APIs to make your life significantly easier. You can download Apache Axis2 from Apache.org. This tutorial uses version 0.94, but later versions should work.

Apache Axis2 Rampart module -- Security for the Axis2 web services engine is provided through the Rampart module, which is not included in the default installation. Download this module from the Apache Download Mirrors.

Apache WSS4J -- Although Axis itself will use Rampart, at some point you will need to reference the WSS4J classes direction. Download the WSS4J package.

Java 2 Standard Edition version 1.4.2 or higher -- All of these tools are Java-based, as are the services and clients you'll build in this tutorial. Download the J2SE SDK.

TCPMon (optional) -- It's always easier to understand what's going on in a web service application when you can actually see the messages. Download the TCP Monitor so you can see the messages coming to and from the web service.

GnuPG (optional) -- All of the message signing we'll be doing is covered by Axis2 and by Java itself, but if you want to play with signing individual documents, as we'll briefly demonstrate, download GnuPG.

You'll also need a Web browser and a text editor.


Overview

Before we talk about securing a service, it's useful to know exactly what pieces make up that service to know what has to be done.

The story so far

This tutorial series has followed the exploits of the staff of the Daily Moon newspaper, which has discovered a new way of working in the form of web services. It all started in the classifieds department, which decided to enable others to access its systems through the use of SOAP messages -- XML messages that can be sent over HTTP.

For example, a request for the number of classified ads in the "for sale" subcategory might look like Listing 1.

Listing 1. A sample SOAP message
<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/SOAP-envelope"> 
 <env:Header>
 </env:Header>
 <env:Body>
  <cms:getNumberOfArticles xmlns:cms="http://www.daily-moon.com/cms">
    <cms:category>classifieds</cms:category>
    <cms:subcategory>forsale</cms:subcategory>
  </cms:getNumberOfArticles>
 </env:Body>
</env:Envelope>

The overall message is called the Envelope, the contents of which consist of the Header and the Body. The Header contains information about the message itself, such as routing information, or information intended to be processed by "SOAP intermediaries", or services between the sender and the ultimate receiver, who may process the message. (In this case, see any of those headers, but that's where our security information is going to go.) The Body of the message includes the "payload", which includes the actual data to be passed to the web service.

In this case, the payload is the getNumberOfArticles element and its contents.

Gene and Frances, from the newspaper's IT department, have put together a system for serving web services requests, as well as the infrastructure for discovering and automatically creating clients for the services. Now the newspaper's publisher, Rudy, is insisting that they find a way to prevent unauthorized access to these systems.

The need for security

The basic SOAP specification does not provide for securing messages, leaving that task for extended specifications. The trouble lies in the nature of a web services application. In most cases, we are dealing with SOAP over HTTP, which means that each message has to travel through one or more intermediate nodes, any one of which can read and/or alter a message. And that's assuming that the SOAP request itself was a direct one. In some cases, SOAP messages are specifically designed to travel through more than one node before arriving at their final destination.

The end result is that we need a way to prevent someone other than the intended receiver from reading sensitive information, in order to prevent eavesdropping. We also need a way to prevent someone other than the intended sender from sending messages, in order to prevent unauthorized access.

The SOAP specification provides a means for adding security information -- we add information to an Envelope's Header element -- but does not specify what that information should be. To take care of that, we need WS-Security.

The pieces of WS-Security

There are three major problems involved in securing SOAP message exchanges, and WS-Security provides answers for all of them, but not directly. It is, in fact, a specification that talks not about how to protect the message, but how to let the receiver know how you've protected the message. To do the actual protecting, WS-Security references additional specifications. Let's look at how that works.

The first problem is to identify and authenticate the client. Because there are a lot of different ways to do create security tokens, WS-Security does not specify any particular means, but rather defines how different security tokens should be transferred within SOAP messages. In other words, it lets the receiver know how to extract security tokens from the message for processing.

The second problem is ensuring integrity of the message. WS-Security uses digital signatures for that, employing the XML Signature specification rather than inventing something new. XML Signature is a W3C recommendation that provides a mechanism for digitally signing XML documents.

The third problem is keeping the message safe from eavesdropping while it's in transit. Once again, WS-Security employs another W3C standard, this time XML Encryption, which provides a mechanism to encrypt XML documents.

In this tutorial, we'll see how using these standards affects the actual SOAP messages used, as Gene and Frances work to secure the existing Classifieds' service.

The current service

Before we look at making changes, it's useful to see where Gene and Frances are starting out. The Classifieds' service is implemented using Axis2, which means that it's contained in an *.aar file. The CMSService.aar file consists of three files, as shown in Listing 2.

Listing 2. The contents of the original service
CMSService.class
meta-inf/Manifest.MF

meta-inf/services.xml

The class itself is straightforward, taking in a SOAP message that lists a category and returning a SOAP message that includes the number of ads for that category. It performs this function as defined by the services.xml file (see Listing 3).

Listing 3. The original services.xml file
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
"org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

Securing the service involves touching only the services.xml file; Gene and Frances won't have to touch the actual Java class at all.

The current client

The client itself is pretty straightforward, and simply makes and displays the request, as shown in Listing 4:

Listing 4. The original client class
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;

public class ClassifiedClient {
    private static EndpointReference targetEPR = 
           new EndpointReference(
               "http://localhost:8888/axis2/services/CMSService");

    public static OMElement getNumOfArticlesOMElement() {
        SOAPFactory fac = OMAbstractFactory.getSOAP12Factory();
        OMNamespace omNs = fac.createOMNamespace(
                "http://daily-moon.com/cms", "cms");
        OMElement method = fac.createOMElement("getNumberOfArticles",
                                                omNs);
        OMElement value = fac.createOMElement("category", omNs);
        value.addChild(fac.createOMText(value, "classifieds"));
        method.addChild(value);

        return method;
    }

    public static void main(String[] args) {
        try {
            OMElement payload = 
               ClassifiedClient.getNumOfArticlesOMElement();
  
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

            ServiceClient sender = new ServiceClient();

            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);

            String response = result.getText();
            System.out.println("There are "+response+
                               " classifieds at the moment.");
        } catch (Exception e) { 
        	System.out.println(e.toString());
        }
    }
}

Note that Gene has changed the endpoint port to 8888, rather than 8080, the port on which Geronimo is listening. He's done that in order to insert an additional step so that he can see the messages flying back and forth.

Seeing the messages

To see the actual SOAP messages, download TCPMon from http://ws.apache.org/commons/tcpmon/download.cgi. (Yes, Axis2 comes with SOAPMonitor, but Gene discovered the hard way that aside from the hassle in setting things up, it shows the SOAP but not necessarily the raw messages, which we'll specifically want to see.)

After downloading, decompress the application and run the tcpmon-1.0-bin\build\tcpmon.bat file. Click the Admin tab and create a new listener, as seen in Figure 1.

Figure 1. The TCPMon Admin tab
The TCPMon Admin tab

Choose 8888 as the port to listen to, and specify 8080 as the target point, so that TCPMon sits between the client and the server. Click Add, and then click the Port 8888 tab. Click the XML Format checkbox. Now when Frances executes the client, Gene can see the request and the response, as in Figure 2.

Figure 2. The original request and response
The original request and response

Before moving on, let's take a quick look at the actual messages, so we can see what changes.

The messages

The messages themselves are very straightforward. The request, as seen in Listing 5, simply asks for the number of classified ads in the system:

Listing 5. The original request
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <cms:getNumberOfArticles 
                    xmlns:cms="http://daily-moon.com/cms">
            <cms:category>classifieds</cms:category>
         </cms:getNumberOfArticles>
      </soapenv:Body>
   </soapenv:Envelope>

The response is equally straightforward, as you can see in Listing 6:

Listing 6: The original response
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope xmlns:soapenv=
           "http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <resp:numberOfArcticles 
               xmlns:resp="http://daily-moon.com/cms/"  
               xmlns:tns="http://ws.apache.org/axis2"
                            >42</resp:numberOfArcticles>
      </soapenv:Body>
   </soapenv:Envelope>

In both of these messages, Frances will place additional information in the Header element for the server (or the client) to process.

At the moment, anyone can send a request to the service and get a response, and that's what makes Rudy nervous. He wants the service set up so that only authorized users can get information, and so that competitors can't intercept the information. Rudy figures that this is a good proof-of-concept system. He's really more worried about more complex systems, such as those that add content or access the accounting system. But the concepts are the same.

To provide that security, Gene and Frances need to use encryption and its related technology, signatures.


Encryption and signatures

The majority of security measures involve one form of encryption or another, or encryption worked into a digital signature, so before Frances let's Gene start mucking with the service's security configuration, she wants to make sure they understand what they're dealing with.

Types of encryption

Encryption is the process of obscuring information to make it unreadable without special knowledge. History has known many different types of encryption. Modern encryption usually is a well-defined sequence of transformations applied to a message and some form of "key". The result is unreadable gibberish. Decryption is a reverse process and also involves a key, so by keeping the key secret one can be reasonable sure no one else can read encrypted message. Modern encryption methods can be classified according to whether they use one or two keys.

In a symmetric key algorithm (for example, DES), the sender and receiver must have a shared key set up in advance and kept secret from all other parties; the sender uses this key for encryption, and the receiver uses the same key for decryption. In this case, the key itself is unimportant, except that it should be known by the two parties involved, and only those two parties.

In an asymmetric key algorithm (such as RSA), there are two separate keys: a public key is published and well-known to belong to a particular individual (or organization), while a corresponding private key is kept secret. A message encrypted by the public key can only by decrypted by the public key, so anyone can send a private message to a particular individual. But the reverse is also true, so a message that can be decrypted by an individual's public key must have been sent by that individual. We'll see how this comes into play in encrypting and signing SOAP messages

.

Encrypting a file

Gene decides to start by seeing how the actual message text is affected by encryption. He starts with a text file, msg.txt, consisting of single line, as you can see in Listing 7.

Listing 7. The target text
Hello, world!

To make things simple, he uses the free GnuPG program, executing the command shown in Listing 8.

Listing 8. The encryption command
gpg.exe -c -a --cipher-algo 3DES msg.txt

This command causes the program to use the symmetric key algorithm 3DES with to encrypt the file. The program asks for passphrase, which Gene enters as "password", and then produces the file msg.txt.asc. You can see the contents of this file in Listing 9.

Listing 9. The encrypted file
-----BEGIN PGP MESSAGE-----
Version: GnuPG v1.4.2.2 (MingW32)

jA0EAgMCqFjZXeujyOJgySoKQ2qhpCpGERKpFn0iKms4kwjpI51BLcoTyH4p61YJ
kDAiRMbC6PfCBmg=
=G4EN
-----END PGP MESSAGE-----

Certainly nobody would guess the original text from that! Encouraged, Gene moves on to look at the issue of digital signatures.

How signatures work

Digital signatures use encryption techniques, but the purpose of signing is different. Rather than obscuring the message, a signature gives the receiver confidence in two pieces of information: the sender of the message, and the message itself.

It works like this. The sender encrypts the message with his or her private key. This "signature" is then sent to the recipient, along with original message. The recipient tries to verify the signature, which means decrypting signature with the sender's public key, and comparing the results to the original message. If this process is successful, the recipient can be sure only the sender can be the originator of the message, because nobody except the sender has his or her private key. What's more, if the original message had changed in transit, the decrypted signature wouldn't match it, so successful signature verification also means that the message hasn't been tampered with.

Usually, instead of signing the whole message, the sender calculates a "digest" of the message (using a cryptographic hash function), signs that, and passes that along with the unencrypted message. The receiver calculates the digest of the received message and compares it to the decrypted digest of the signature. This provides the same effect without having to essentially double the size of each message. (It also cuts down on processing time to create and verify the signatures.)

Signing a file

Emboldened, Gene decides to see this in action. His intention is to digitally sign the msg.txt file he'd previously encrypted. Because it makes signing a file simple, he'll use the same GnuPG software, even though he'll later use a different technique to create the keys used by the actual application.

The first step is to create the key pair using the command in Listing 10.

Listing 10. Generating a key pair
gpg.exe --gen-key

The program asks a lot of question about the key, such as Gene' name, email, and so on. He settles on the default key parameters (the DSA algorithm and the 2048 bit key length), and supplies the name "Jon Dow". This operation stores the keys in a keystore file in Gene's home folder.

Now he can sign the message. He uses the command shown in Listing 11.

Listing 11. Signing the document
gpg.exe --clearsign -u "Jon Dow" msg.txt

This time, the program asks for the password associated with "Jon Dow"'s private key, then produces the msg.txt.asc file, as shown in Listing 12.

Listing 12. The signed document
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello, world!
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.2 (MingW32)

iD8DBQFEhftF06oTl3UESDQRArHsAJ0bE2qUEeVb5IDz4gQuRCgOes6v7gCfQhbJ
l356yO+YTkJUJZx4KoTTzok=
=ld3Y
-----END PGP SIGNATURE-----

A person receiving this message would know to decrypt the signature using "Jon Dow"'s public key, hash the unencrypted message (using SHA1), and compare the two.

Now that they understand how encryption and signatures work, Gene and Frances are ready to move on to securing the actual service.


Securing the service

Securing the service involves a number of steps that must take place before the first secure message can be sent, and while none of them are specific to the actual WS-Security specification (rather than the software the team is using to generate the messages), these steps are crucial, and will, in one form or another, take place for any WS-Security installation.

Generating the keystore

Now that he's seen signatures and encryption in action, Gene needs to start preparing the team's own installation. He needs to start by creating the keystore, which will include all of the private key-public key pairs that may be needed. To do that, he'll use the keytool application that comes with the JDK.

To create a new key and generate a keystore, he executes the following commands, as seen in Listing 13.

Listing 13. Creating a key pair and keystore
>cd %JAVA_HOME%\bin
>keytool -genkey -keystore mykeys.jks -alias gene
Enter keystore password:  mykeystorepassword
What is your first and last name?
  [Unknown]:  Gene Telluride
What is the name of your organizational unit?
  [Unknown]:  Information Technologies
What is the name of your organization?
  [Unknown]:  The Daily Moon
What is the name of your City or Locality?
  [Unknown]:  New York
What is the name of your State or Province?
  [Unknown]:  NY
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Gene Telluride, OU=Information Technologies, O=The Daily Moon, 
L=New York, ST=NY, C=U
S correct?
  [no]:  yes

Enter key password for <gene>
        (RETURN if same as keystore password):  mypassword

The command line tells the tool to generate a key pair and store it in the mykeys.jks file. The key pair has an alias of gene, which lets us easily refer to it. Frances can create her key and store it in the same file, mykeys.jks.

Now they're ready to start working on securing the service itself.

Enabling security

The first step in adding WS-Security to the service is to enable it on the server. Apache Axis2, the web services engine on which the team is running its services, is built in a modular way, and the WS-Security module is called Rampart (see Prerequisites for download information). Once you have downloaded Rampart, place the rampart-1.0.mar file in the modules directory for your Axis installation. For example, Gene's installation has the modules folder at C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\modules.

Next, Gene needs to make this module globally available, because in the "handler chain" that works behind the scenes of Axis2, it needs to engage before the message can be directed to a specific service. Restart Geronimo and log in to the Axis2 administration page at http://localhost:8080/axis2/axis2-admin/login . (The username is admin and the password is axis2.) Click Engage Module/For all services and select rampart-1.0. Click Engage, as you can see in Figure 3.

Figure 3. Engaging the Rampart module
engaging the Rampart module

You can also engage the Rampart module by adding the it to the axis2.xml file, as you'll see when we look at securing the client.

Set security on the service

Now that the infrastructure is in place, Frances can start securing the actual service. First, she shuts down Geronimo, because she wants to update the services.xml file that's located in the CMSService.aar archive. (She has the option of updating and re-uploading the service, but she's chosen to alter the archive directly.) The paper's installation has the *.aar file at the location C:\SW\geronimo-1.0\config-store\32\war\WEB-INF\services\CMSService.aar. She updates the services.xml file to require a timestamp, as seen in Listing 14.

Listing 14. Adding a timestamp to the service
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

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

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

    <operation name="getNumberOfArticles">
        <messageReceiver class=
         "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

Axis2 enables Frances to specifically control messages flowing both into and out of the service. In this case, she's told the web services engine to require incoming messages to include a Timestamp, and to include a Timestamp in the outgoing messages returned to the client.

In a moment, we'll see the effect this change has on the messages passed between server and client, but when Frances attempts to run a test, TCPMon shows that the server returns an error rather than the expected information, as you can see in Listing 15.

Listing 15. Missing security headers
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope 
         xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
         xmlns:wsa="http://www.w3.org/2005/08/addressing">
      <soapenv:Header>
         <wsa:ReplyTo>
            <wsa:Address>
              http://www.w3.org/2005/08/addressing/anonymous
            </wsa:Address>
         </wsa:ReplyTo>
         <wsa:MessageID>
            urn:uuid:1CA9E94A9C7FE9D5B311507328796251
         </wsa:MessageID>
         <wsa:Action>
            http://www.w3.org/2005/08/addressing/fault
         </wsa:Action>
      </soapenv:Header>
      <soapenv:Body>
         <soapenv:Fault>
            <faultcode>soapenv:Client</faultcode>
            <faultstring>WSDoAllReceiver: Request does not 
               contain required Security header</faultstring> 
            <detail>
               <Exception>org.apache.axis2.AxisFault: WSDoAllReceiver: 
                   Request does not contain required Security 
                   header
 at ...
               </Exception>
            </detail>
         </soapenv:Fault>
      </soapenv:Body>
   </soapenv:Envelope>

The important thing here is that Frances now knows it's working; the engine won't accept messages unless they conform to the security she's configured for the service.

Now she can move on to the client.

Securing the client

In many ways, the client is also a server of sorts, in that it also sends and receives SOAP messages, so perhaps it should come as no surprise that Frances' first step in securing the client is to add the rampart-1.0.mar to the client installation. To do that, she first creates a new directory, <CLIENT_HOME>\axis-repo\modules, where <CLIENT_HOME> is the directory in which the ClassifiedClient.class file is located. She then adds the rampart-1.0.mar file to that directory. She also creates a second directory, <CLIENT_HOME>\axis-repo\conf, in which she creates a new file, axis2.xml. The file contains the code seen in Listing 16.

Listing 16. The original axis2.xml file
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="ramart"/>
    

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

<!--    <parameter name="InflowSecurity">
      <action>
        <items>Timestamp</items>
      </action>
    </parameter> --> 

    <!-- ================================================= -->
    <!-- Parameters -->
    <!-- ================================================= -->
    <parameter name="hotdeployment"
 locked="false">true</parameter>
    <parameter name="hotupdate" locked="false">false</parameter>
    <parameter name="enableMTOM" locked="false">true</parameter>
    <!-- Uncomment this to enable REST support -->
    <!--    <parameter name="enableREST"
 locked="false">true</parameter>-->


    <parameter name="userName" locked="false">admin</parameter>
    <parameter name="password" locked="false">axis2</parameter>

    <!-- ================================================= -->
    <!-- Message Receivers -->
    <!-- ================================================= -->
    <!--This is the Deafult Message Receiver for the system , 
if you want to have MessageReceivers for -->
    <!--all the other MEP implement it and add the correct entry 
to here, so that you can refer from-->
    <!--any operation -->
    <!--Note : You can ovride this for particular service by 
adding the same element with your requirement-->
    <messageReceivers>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-only"
                        
 class="org.apache.axis2.receivers.RawXMLINOnlyMessageReceiver"/>
        <messageReceiver mep="http://www.w3.org/2004/08/wsdl/in-out"
                        
 class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </messageReceivers>
    <!-- ================================================= -->
    <!-- Transport Ins -->
    <!-- ================================================= -->
    <transportReceiver name="http"
                      
 class="org.apache.axis2.transport.http.SimpleHTTPServer">
        <parameter name="port" locked="false">6060</parameter>
        <!--If you want to give your own host address for EPR
 generation-->
        <!--uncommet following paramter , and set as you required.-->
        <!--<parameter name="hostname"
 locked="false">http://myApp.com/ws</parameter>-->
    </transportReceiver>

    <transportReceiver name="tcp"
                       class="org.apache.axis2.transport.tcp.TCPServer">
        <parameter name="port" locked="false">6061</parameter>
        <!--If you want to give your own host address for EPR
 generation-->
        <!--uncommet following paramter , and set as you required.-->
        <!--<parameter name="hostname"
 locked="false">tcp://myApp.com/ws</parameter>-->
    </transportReceiver>

    <!-- ================================================= -->
    <!-- Transport Outs -->
    <!-- ================================================= -->

    <transportSender name="tcp"
                    
 class="org.apache.axis2.transport.tcp.TCPTransportSender"/>
    <transportSender name="local"
                    
 class="org.apache.axis2.transport.local.LocalTransportSender"/>
    <transportSender name="jms"
                     class="org.apache.axis2.transport.jms.JMSSender"/>
    <transportSender name="http"
                    
 class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">
        <parameter name="PROTOCOL"
 locked="false">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding"
 locked="false">chunked</parameter>
    </transportSender>
    <transportSender name="https"
                    
 class="org.apache.axis2.transport.http.CommonsHTTPTransportSender">
        <parameter name="PROTOCOL"
 locked="false">HTTP/1.1</parameter>
        <parameter name="Transfer-Encoding"
 locked="false">chunked</parameter>
    </transportSender>

    <!-- ================================================= -->
    <!-- Phases  -->
    <!-- ================================================= -->
    <phaseOrder type="inflow">
        <!--  System pre defined phases       -->
         <phase name="Transport">
            <handler name="RequestURIBasedDispatcher"
                    
 class="org.apache.axis2.engine.RequestURIBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
            <handler name="SOAPActionBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPActionBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
        </phase>
        <phase name="Security"/>
        <phase name="PreDispatch"/>
        <phase name="Dispatch"
 class="org.apache.axis2.engine.DispatchPhase">
            <handler name="AddressingBasedDispatcher"
                    
 class="org.apache.axis2.engine.AddressingBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="SOAPMessageBodyBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
            <handler name="InstanceDispatcher"
                     class="org.apache.axis2.engine.InstanceDispatcher">
                <order phase="PostDispatch"/>
            </handler>
        </phase>
        <!--  System pre defined phases       -->
        <!--   After Postdispatch phase module author or or 
service author can add any phase he want      -->
        <phase name="OperationInPhase"/>
    </phaseOrder>
    <phaseOrder type="outflow">
        <!--      user can add his own phases to this area  -->
        <phase name="OperationOutPhase"/>
        <!--system predefined phase-->
        <!--these phase will run irrespective of the service-->
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
    </phaseOrder>
    <phaseOrder type="INfaultflow">
        <phase name="PreDispatch"/>
        <phase name="Dispatch"
 class="org.apache.axis2.engine.DispatchPhase">
            <handler name="RequestURIBasedDispatcher"
                    
 class="org.apache.axis2.engine.RequestURIBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="SOAPActionBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPActionBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="AddressingBasedDispatcher"
                    
 class="org.apache.axis2.engine.AddressingBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>

            <handler name="SOAPMessageBodyBasedDispatcher"
                    
 class="org.apache.axis2.engine.SOAPMessageBodyBasedDispatcher">
                <order phase="Dispatch"/>
            </handler>
            <handler name="InstanceDispatcher"
                     class="org.apache.axis2.engine.InstanceDispatcher">
                <order phase="PostDispatch"/>
            </handler>
        </phase>
        <!--      user can add his own phases to this area  -->
        <phase name="OperationInFaultPhase"/>
    </phaseOrder>
    <phaseOrder type="Outfaultflow">
        <!--      user can add his own phases to this area  -->
        <phase name="OperationOutFaultPhase"/>
        <phase name="PolicyDetermination"/>
        <phase name="MessageOut"/>
    </phaseOrder>
    </axisconfig>

Most of this code is boilerplate, borrowed from other Axis2 examples. In the bold section at the top, however, Frances adds to tell the client to add a Timestamp to the message that it sends to the server. She opts not to deal with the Timestamp returned by the server, at least for the moment. Unlike the service, however, the client won't automatically obey these directives. She's got to make changes to the actual class.

Changes to the client class

In order for the client class to make the changes specified in the axis2.xml file, it has to know about them. To that end, Frances adds the configuration into the process of creating the ServiceClient, as seen in Listing 17.

Listing 17. Calling the new configuration from ClassifiedClient.java
...
    public static void main(String[] args) {
        try {
            OMElement payload = 
                ClassifiedClient.getNumOfArticlesOMElement();
            ConfigurationContext 
                 configContext = ConfigurationContextFactory
                      .createConfigurationContextFromFileSystem(
                                               "axis-repo", null); 
            Options options = new Options();
            options.setTo(targetEPR);
            options.setTransportInProtocol(Constants.TRANSPORT_HTTP);

            ServiceClient sender = 
                  new ServiceClient(configContext, null);

            sender.setOptions(options);
            OMElement result = sender.sendReceive(payload);

            String response = result.getText();
            System.out.println("There are "+response+
                                  " classifieds at the moment.");
        } catch (Exception e) { 
        	System.out.println(e.toString());
        }
    }
}

First, Frances creates a new ConfigurationContext, which enables the ServiceClient to look for a new configuration. But in order to make it happen, she'll need to change the way she calls the actual client class.

Pulling it all together

In order for the client to properly call the Rampart module, it needs to know where to find the configuration file, and where to find any other repository items, such as the *.mar file itself. To do that, Frances adds more detail to the script that sets her classpath and runs the client class, as seen in Listing 18.

Listing 18. Calling the class
echo off
SET CLASSPATH=C:/SW/axis2/lib/XmlSchema-1.0.2.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-api-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axiom-impl-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/axis2-kernel-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-codec-1.3.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-httpclient-3.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/commons-logging-1.0.4.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/
                             geronimo-spec-activation-1.0.2-rc4.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/
                             geronimo-spec-javamail-1.3.1-rc5.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/jaxen-1.1-beta-8.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/log4j-1.2.13.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/neethi-1.0.1.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/stax-api-1.0.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wsdl4j-1.5.2.jar
SET CLASSPATH=%CLASSPATH%;C:/SW/axis2/lib/wstx-asl-2.9.3.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/wss4j-1.5.0.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xmlsec-1.3.0.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/
                             commons-discovery-0.2.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/
                             bcprov-jdk13-132.jar
SET CLASSPATH=%CLASSPATH%;C:/sw/ClassifiedClient/lib/xalan.jar
SET CLASSPATH=%CLASSPATH%;.

java.exe -Daxis2.xml=axis-repo/conf/axis2.xml 
         -Daxis2.repo=axis-repo ClassifiedClient

Notice that Frances also adds several *.jar files from the WSS4J distribution (see Prerequisites for download information).

Now she's ready to try the request once more.

The request

Running the request shows a normal SOAP message, with one exception, as seen in Listing 19.

Listing 19. A Timestamped SOAP message
<?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-29987161">
            <wsu:Created>2006-06-19T16:22:28.578Z</wsu:Created>
            <wsu:Expires>2006-06-19T16:27:28.578Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security> 
   </soapenv:Header>
   <soapenv:Body>
      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">
         <cms:category>classifieds</cms:category>
      </cms:getNumberOfArticles>
   </soapenv:Body>
</soapenv:Envelope>

Now, for the first time, Frances sees a Security header in her messages. In this case, it's just a Timestamp, which shows when the message was created. The mustUnderstand attribute means that if the server doesn't know what to do with this Timestamp element, it must reject the message.

Timestamps are perhaps the simplest element of WS-Security. They provide a way to limit the lifespan of messages, preventing malcontents from intercepting messages, altering them at their leisure, and sending them on. In this case, the Timestamp expires five seconds after the creation of the message, so if the message is older than that, the message must be rejected. (Yes, a malcontent can still alter the Timestamp values, but we'll deal with that when we get to signatures.)

The response

As specified in the service, the response also has a Timestamp, as seen in Listing 20.

Listing 20. The response
<?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-22347273">
              
 <wsu:Created>2006-06-19T16:22:29.281Z</wsu:Created>
              
 <wsu:Expires>2006-06-19T16:27:29.281Z</wsu:Expires>
            </wsu:Timestamp>
            <wsse11:SignatureConfirmation xmlns:wsse11=
"http://docs.oasis-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-
secext-1.1.xsd" xmlns:wsu="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-
1.0.xsd" wsu:Id="SigConf-5759024" />
         </wsse:Security> 
      </soapenv:Header>
      <soapenv:Body>
         <resp:numberOfArcticles 
                     xmlns:resp="http://daily-moon.com/cms/" 
                     xmlns:tns="http://ws.apache.org/axis2"
                >42</resp:numberOfArcticles>
      </soapenv:Body>
   </soapenv:Envelope>

The response includes the Timestamp, as specified, but also shows that the security information has been processed and verified, even though Frances hasn't configured the client to check either one of these facts.

Notice that in both cases, the actual messages were left intact.


Signing messages

Now, at this point, Frances has added a Timestamp to both the outgoing and incoming messages, but there's nothing to stop someone from simply changing its value and retransmitting it. To solve that problem (and any other problems that arise from information that may have been changed) Frances needs to look at signing her messages.

How signing messages works

As we've previously seen, signing a message involves creating a version of the data that's been encrypted in a known way, so that decrypting it provides a value you can compare to the original. For example, say that Frances wants to digitally sign the Timestamp element in her messages so that the server can verify that they haven't been tampered with or misappropriated in some way.

To do that, she's going to institute a process that will take several steps.

First, she will sign the message (or portion of the message). To do that, she'll use the axis2.xml file to specify a user as the signer. Axis2 will take that information and do two things with it. First, it will feed the user alias to a "callback class", which will return the password for that user. Armed with that password, Axis2 will then retrieve that user's private key from the keystore we created earlier.

Using the private key, Axis2 encrypts, or signs, the relevant part of the message and adds the signature to the message. It then sends the message. When the service receives the message, it does almost the same thing; it accesses the keystore to get the public key for that user, and then it verifies the signature.

Note that if the service were going to send back content that has been signed, these roles would be reversed for the return trip.

Let's look at getting this set up.

The callback class

The first step is to create the callback class. In a real situation, this class might access an LDAP directory or use other methods for associating a username with a password, but Frances is starting with a proof-of-concept, so she'll create a simple callback class that returns arbitrary values, as you can see in Listing 21.

Listing 21. PWCallback.java, the callback class
import org.apache.ws.security.WSPasswordCallback;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

public class PWCallback implements CallbackHandler {

   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];
                if (pc.getIdentifer().equals("gene")) {
                    pc.setPassword("mypassword");
                } else if (pc.getIdentifer().equals("frances")) {
                    pc.setPassword("francespassword");
                } else {
                    throw new UnsupportedCallbackException(
                                   callbacks[i], "Unknown user");
                }
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                        "Unrecognized Callback");
            }
        }
    }
}

What the class does in the handle() method isn't important; all that's important is that it either sets the password on the WSPasswordCallback object or it throws an exception.

The properties file

Next Frances has to find a way to tell Axis2 where to find the keystore, and what class should actually perform all of this cryptographic wizardry. To do that, she creates a properties file, security.properties, as seen in Listing 22:

Listing 22. The security.properties file
org.apache.ws.security.crypto.provider=org.apache.ws.security.compo
nents.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=mykeystorepa
ssword
org.apache.ws.security.crypto.merlin.file=mykeys.jks

After specifying the provider, the properties file defines the type of keystore -- in this case, jks, the proprietary format that comes with Java -- the password for the keystore, and the name of the actual keystore file, which for simplicity's sake she puts in the same directory as the client class file.

The axis2.xml file

Now she needs to let the axis2.xml file what she's got in mind for outgoing messages, as you can see in Listing 23.

Listing 23. The axis2.xml file, with signature
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="rampart"/>

    <parameter name="OutflowSecurity">
      <action>
        <items>Signature</items>
        <user>gene</user><passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier>SKIKeyIdentifier</signatureK
eyIdentifier>
        <signatureParts>{Element}{http://schemas.xmlsoap.org
/soap/envelope/}Body</signatureParts>
      </action>
    </parameter>
<!--
    <parameter name="InflowSecurity">
      <action>
        <items>Timestamp</items>
      </action>
    </parameter>
-->
...

In this case, instead of telling the client to add a Timestamp, she's telling it to add a Signature. Seeing that, the client looks at the file specified in signaturePropFile and uses the information found there -- along with the passwordCallbackClass -- to get the password for the gene user. From there, it pulls gene's private key and signs only the part of the message specified in the signatureParts element. In this case, that means that the element represented by the Body (as opposed to just that element's content), which is part of the http://schemas.xmlsoap.org/soap/envelope/ namespace.

You can sign any part of the message. For example, people often sign the Timestamp, if present.

The request

So what do all of these changes mean for the messages produced by the client? You can see the resulting request in Listing 24.

Listing 24. The signed request
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
        "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <ds:Signature xmlns:ds="..." Id="Signature-8789796">
            <ds:SignedInfo>
               <ds:CanonicalizationMethod Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                 "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#id-17764792">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                     "http://www.w3.org/2000/09/xmldsig#sha1" />
                  <ds:DigestValue
                  >wg+9KsR6BVBiO/hakJJwMdtU7+I=</ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>

 <ds:SignatureValue>hom9Enzu3yHBuaF...</ds:SignatureValue>
            <ds:KeyInfo Id="KeyId-19475750">
               <wsse:SecurityTokenReference xmlns:wsu=".." 
                      wsu:Id="STRId-31156635">
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis
-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body xmlns:wsu="..." wsu:Id="id-17764792">
      <cms:getNumberOfArticles xmlns:cms="http://daily-moon.com/cms">
         <cms:category>classifieds</cms:category>
      </cms:getNumberOfArticles>
   </soapenv:Body>
</soapenv:Envelope>

I've snipped out namespace values to make this a bit more readable, but let's go through it bit by bit. The Security element contains all of the security information, of course, starting with the Signature. The signature starts with the information on what was actually signed. Jumping forward just a little bit, the Reference element includes a URI attribute, which refers back to the id attribute for the Body, which is, remember, what Frances told the client to sign. So that tells the service what information was actually signed.

Moving back up, the first step in signing content is to canonicalize it -- remove extraneous text nodes, and so on -- but there are actually two ways to do that, inclusive and exclusive, the difference being in how each method handles namespace declarations. So the CanonicalizationMethod element specifies which method the signature uses.

We then move to the SignatureMethod, which specifies, as the name suggests, the method used to sign the relevant data.

The Reference element includes information on all of the steps that were taken to arrive at the final content to sign, in order, so that the verification process can take the same steps and (hopefully) arrive at the same SignatureValue.

The KeyInfo provides either the actual key used to sign the data or a reference to the key.

Making changes to the service

Now the client is creating the signature, but the service doesn't know what to do with it. Frances is about to change that.

In essence, the service needs to perform many of the same steps the client performed; it needs to be able to find passwords and keys in the keystore, so Frances starts by adding the mykeys.jks, PWCallback.class and security.properties files to the CMSService.aar file. You don't have to use the same class and keystore you used for the client, but in this case, she does it for the sake of convenience.

She also adds the bcprov-jdk13-132.jar, wss4j-1.5.0.jar, and xmlsec-1.3.0.jar to the lib directory of the Axis2 application. (These files come from the WSS4J distribution.)

Frances then has to set the service definition (in services.xml) to recognize that signed data is coming its way. She does that by making the changes shown in Listing 25.

Listing 25. Telling the service to expect signed data
<service name="CMSService">

    <description>
   This is a sample web service for the newspaper's Content Managment System.
    </description>

    <parameter name="ServiceClass"
 locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Signature</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>
           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

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

    <operation name="getNumberOfArticles">
        <messageReceiver
 class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

These changes are enough to let the service know what to expect and what to do with the signed data.

The response

The response is a document that includes a Timestamp, as specified in the OutFlowSecurity parameter, but also includes information about the verification of the signature, as seen in Listing 26.

Listing 26. The response
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
         "http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <wsu:Timestamp xmlns:wsu="..." wsu:Id="Timestamp-27995990">
            <wsu:Created>2006-06-19T23:56:55.214Z</wsu:Created>
            <wsu:Expires>2006-06-20T00:01:55.214Z</wsu:Expires>
         </wsu:Timestamp>
         <wsse11:SignatureConfirmation xmlns:wsse11="..." 
             xmlns:wsu="..." Value="hom9Enzu3yHBuaigFl26b6A+5hy..." 
             wsu:Id="SigConf-25877728" />
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body>
      <resp:numberOfArcticles xmlns:resp="http://daily-moon.com/cms/" 
  
 xmlns:tns="http://ws.apache.org/axis2">42</resp:numberOfArcticles>
   </soapenv:Body>
</soapenv:Envelope>

Now let's look at adding encryption to the picture.


Adding encryption

Frances is pleased with the process of verifying part of the message using signatures, but there's still no way to obscure information so that competitors and other miscreants can't read it. To take care of that, she'll have to add encryption to the application.

Altering the service

This time, she starts with the service. She's already added all of the additional classes the application needs, so all she needs to change is the services.xml file, as you can see in Listing 27.

Listing 27. Adding encryption to the service
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Timestamp Signature
 Encrypt</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>
           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
        "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

Here Frances has told the service that messages coming in will have had a Timestamp added, and then they will have been signed, and then they will have been encrypted -- in that order.

Now she just has to tell the client to do it.

Altering the client

Because she's already laid the groundwork, adding encryption to the client is also straightforward, and involves just a simple change to the axis2.xml file, as you can see in Listing 28.

Listing 28. Adding encryption to the client
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="rampart"/>
    

    <parameter name="OutflowSecurity">
      <action>
        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>{Element}{http://schemas.xmlsoap.org/soap/env
elope/}Body</signatureParts>
       
 <optimizeParts>//xenc:EncryptedData/xenc:CipherData/xenc:Ciph
erValue</optimizeParts>
      </action>
    </parameter>

    <!-- ================================================= -->
    <!-- Parameters -->
    <!-- ================================================= -->
    <parameter name="hotdeployment"
 locked="false">true</parameter>
...

Notice that Francis is specifying a different user for encryption than she used for the digital signature. This isn't a requirement, but it is possible. Note also the addition of the optimizeParts element, which specifies how Axis2 should represent the encrypted data in the message.

Let's see how that all plays out.

The request

With everything in place, the message is becoming somewhat complex, as you can see in Listing 29.

Listing 29. The signed, sealed, and encrypted request
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/"
         xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <soapenv:Header>
      <wsse:Security xmlns:wsse="..." soapenv:mustUnderstand="1">
         <xenc:EncryptedKey Id="EncKeyId-229902">
            <xenc:EncryptionMethod Algorithm=
                 "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
            <ds:KeyInfo xmlns:ds="...">
               <wsse:SecurityTokenReference>
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis
-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
            <xenc:CipherData>
              
 <xenc:CipherValue>PpAOXj5P0W8ukm...</xenc:CipherValue>
            </xenc:CipherData>
            <xenc:ReferenceList>
               <xenc:DataReference URI="#EncDataId-30957433" />
            </xenc:ReferenceList>
         </xenc:EncryptedKey>
         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                       Id="Signature-17764792">
            <ds:SignedInfo>
               <ds:CanonicalizationMethod Algorithm=
                      "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                   "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#id-30957433">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                      "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                       "http://www.w3.org/2000/09/xmldsig#sha1" />
                 
 <ds:DigestValue>+ECkM6R4GQ7AQ=...</ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>
            <SignatureValue>DIeP5AxVmfw...</ds:SignatureValue>
            <ds:KeyInfo Id="KeyId-16675983">
               <wsse:SecurityTokenReference
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-21866740">
                  <wsse:KeyIdentifier
 EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-soap-message-security-1.0#Base64Binary"
 ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">
CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>
         <wsu:Timestamp
 xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-
wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-13665843">
            <wsu:Created>2006-06-20T00:46:58.263Z</wsu:Created>
            <wsu:Expires>2006-06-20T00:51:58.263Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body xmlns:wsu="..." wsu:Id="id-30957433">
      <xenc:EncryptedData Id="EncDataId-30957433" Type=
                "http://www.w3.org/2001/04/xmlenc#Content">
         <xenc:EncryptionMethod Algorithm=
           "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
         <xenc:CipherData>
            <xenc:CipherValue>DZ3vWPtabb5vBpZMlEYLPjFc8r2DMJ...
fSjXpBFa7gybNA==</xenc:CipherValue>
         </xenc:CipherData>
      </xenc:EncryptedData>
   </soapenv:Body>
</soapenv:Envelope>

Starting at the bottom, notice that the actual request is missing, or rather Axis2 has replaced it with an EncryptedData element that includes information on how the data was encrypted, as well as the actual encrypted data (in the CypherData and CypherValue) elements.

The data was encrypted with a shared key, which means that the message has to include that key so that it can by decrypted. The shared key has been encrypted with the receiver's public key and embedded in the Header, in the EncryptedKey element. This key also includes a ReferenceList, which includes a DataReference that points back to the data this key was used to encrypt.

So to reverse direction, the receiver (in this case, the server) receives the message, uses its own private key to decrypt the shared key, and then uses the shared key to decrypt the body of the message.

And after all that, what does the response look like?

The response

The response is pretty simple, actually, because Frances didn't set any OutFlowSecurity on the server, as you can see in Listing 30.

Listing 30. The response
<?xml version='1.0' encoding='UTF-8'?>
   <soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/">
      <soapenv:Header />
      <soapenv:Body>
         <resp:numberOfArcticles xmlns:resp=
                "http://daily-moon.com/cms/" xmlns:tns=
                "http://ws.apache.org/axis2"
         >42</resp:numberOfArcticles>
      </soapenv:Body>
   </soapenv:Envelope>

This is a perfectly valid SOAP response, except for one thing. You may remember that Frances has set the client to expect, at the very least, a Timestamp in its own InFlowSecurity. So after all that, the request will still fail unless both the server and the client are producing and expecting the same security methods.


Putting it all together

At this point Frances and Gene have a few disjointed examples, so they decide to put everything together into a single implementation to show to Rudy.

The final service specification

Rudy wants the service to only accept requests from authorized individuals (or entities), and he doesn't want the responses to be readable by competitors. To do that, Gene and Frances set things up as follows:

  1. The client will add a Timestamp, which it will need to sign with the private key of an approved user. This takes care of the authorized access issue, and prevents messages from being intercepted and replayed.
  2. The server will add a Timestamp, but it will also encrypt the body of the response so that eavesdroppers can't see the data that comes back.

Let's look at how it all comes together.

The service

On the service side, Gene sets up the services.xml file as seen in Listing 31.

Listing 31. The final services.xml file
<service name="CMSService">

    <description>
        This is a sample web service for the newspaper's 
        Content Managment System.
    </description>

    <parameter name="ServiceClass" 
               locked="false">CMSService</parameter>

    <parameter name="InflowSecurity">
       <action>
            <items>Timestamp Signature</items>
           
 <passwordCallbackClass>PWCallback</passwordCallbackClass>
           
 <signaturePropFile>security.properties</signaturePropFile>
       </action>
    </parameter>

    <parameter name="OutflowSecurity">
      <action>
        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>
           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body
        </signatureParts>
        <optimizeParts>
            //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData
        </optimizeParts> 
       </action>
    </parameter>

    <operation name="getNumberOfArticles">
        <messageReceiver class=
           "org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
    </operation>

</service>

The InflowSecurity is what the server expects -- a message that has had a Timestamp added and then signed -- and OutflowSecurity is what it will send back to the client -- a message that has been Timestamped and signed, with the data encrypted.

The client

On the client side, Frances sets up the reverse, as you can see in Listing 32.

Listing 32. The final axis2.xml file
<axisconfig name="AxisJava2.0">

    <!-- Engage the security module -->
    <module ref="rampart"/>
    
    <parameter name="OutflowSecurity">
      <action>
        <items>Timestamp Signature</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</
passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <signatureParts>
            {Element}{http://docs.oasis-open.org/wss/2004/01/oasis
-200401-wss-wssecurity-utility-1.0.xsd}Timestamp</signatureParts>
      </action>
    </parameter>

    <parameter name="InflowSecurity">
      <action>
        <items>Timestamp Signature Encrypt</items>
        <user>gene</user>
        <passwordCallbackClass>PWCallback</passwordCallbackClass>
       
 <signaturePropFile>security.properties</signaturePropFile>
        <signatureKeyIdentifier
                        >SKIKeyIdentifier</signatureKeyIdentifier>
        <encryptionKeyIdentifier
                       >SKIKeyIdentifier</encryptionKeyIdentifier>
        <encryptionUser>frances</encryptionUser>
        <signatureParts>
           {Element}{http://schemas.xmlsoap.org/soap/envelope/}Body
        </signatureParts>
        <optimizeParts>
           //xenc:EncryptedData/xenc:CipherValue/xenc:CipherData
        </optimizeParts> 
      </action>
    </parameter>

    <!-- ================================================= -->
    <!-- Parameters -->
    <!-- ================================================= -->
    <parameter name="hotdeployment" locked="false">true</parameter>
...

Now the client will send messages that are timestamped and signed, and insist that any responses must be timestamped, signed and encrypted.

Let's see what that means for the actual messages.

The request

Listing 33 shows the final request.

Listing 33. The final request
<?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">
         <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                                             Id="Signature-5525185">
            <ds:SignedInfo>
               <ds:CanonicalizationMethod Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
               <ds:SignatureMethod Algorithm=
                     "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#Timestamp-1741620">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                         "http://www.w3.org/2000/09/xmldsig#sha1" />
                  <ds:DigestValue>
                     TQSR9wUuJ7rJi582TsbNjiAUqZI=
                  </ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>
             <ds:SignatureValue>aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3Icl
lObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl020To
VtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXdas=
</ds:SignatureValue>
             <ds:KeyInfo Id="KeyId-26644003">
                <wsse:SecurityTokenReference xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd" wsu:Id="STRId-26174005">
                   <wsse:KeyIdentifier EncodingType="http://docs.oasi
s-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Bas
e64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
                </wsse:SecurityTokenReference>
             </ds:KeyInfo>
          </ds:Signature>
          <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/20
04/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
                                          wsu:Id="Timestamp-1741620">
             <wsu:Created>2006-06-22T11:34:02.453Z</wsu:Created>
             <wsu:Expires>2006-06-22T11:39:02.453Z</wsu:Expires>
          </wsu:Timestamp>
       </wsse:Security>
    </soapenv:Header>
    <soapenv:Body>
       <cms:getNumberOfArticles 
                     xmlns:cms="http://daily-moon.com/cms">
          <cms:category>classifieds</cms:category>
       </cms:getNumberOfArticles>
    </soapenv:Body>
 </soapenv:Envelope>

The response

Listing 34 shows the final response.

Listing 34. The final response
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv=
            "http://schemas.xmlsoap.org/soap/envelope/" 
            xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <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">
         <xenc:EncryptedKey Id="EncKeyId-28585008">
            <xenc:EncryptionMethod Algorithm=
                "http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
            <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
            <wsse:SecurityTokenReference>
               <wsse:KeyIdentifier EncodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-
1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2
004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKey
Identifier">Xeg55vRyK3ZhAEhEf+YT0z986L0=</wsse:KeyIdentifier>
            </wsse:SecurityTokenReference>
         </ds:KeyInfo>
         <xenc:CipherData>
            <xenc:CipherValue>NSkylkASezzHSp37izSN3xnxf6v/zwN3C70uU2n
UTNk4a9xYxhNcgiVQuS2/Tm3/x3Jm1d9rj2V8x1uqlKmi89MFifN34SDxaDTMBFzhfRv4
CmQSITEFjY1ySVDvMb7WZszGDhVIGYkjcDkoK+SfWdxyuaUdNUbPgEihSnFVRXs=</xen
c:CipherValue>
         </xenc:CipherData>
         <xenc:ReferenceList>
            <xenc:DataReference URI="#EncDataId-19400027" />
         </xenc:ReferenceList>
      </xenc:EncryptedKey>
      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" 
                                      Id="Signature-17174249">
         <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm=
                     "http://www.w3.org/2001/10/xml-exc-c14n#" />
            <ds:SignatureMethod Algorithm=
                  "http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
               <ds:Reference URI="#id-19400027">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                    "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                       "http://www.w3.org/2000/09/xmldsig#sha1" />
                 
 <ds:DigestValue>HfdufYEGpvPpfz2+HWKui4npV9s=</ds:Di
gestValue>
               </ds:Reference>
               <ds:Reference URI="#SigConf-17122634">
                  <ds:Transforms>
                     <ds:Transform Algorithm=
                        "http://www.w3.org/2001/10/xml-exc-c14n#" />
                  </ds:Transforms>
                  <ds:DigestMethod Algorithm=
                         "http://www.w3.org/2000/09/xmldsig#sha1" />
                 
 <ds:DigestValue>e88WWqudpvW69wN23fgZjQ9ZAio=</ds:Di
gestValue>
               </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>aZLon//vwkw2G2Jxcligxod/CgxMjwtlefZiho
yUz5FpgSY6RUoI5vuHX2unrWV+EVA2vWdtz/Iyq+RS7j4QtE2XTYovxdyiZPbKXNdFKHy
AkpDr0aDLG9rSjyFVcTrUKgAY06t10zi13Daq95nDMH+wAJCYUO0Vor/u0V9Iv7I=</ds
:SignatureValue>
            <ds:KeyInfo Id="KeyId-22768665">
               <wsse:SecurityTokenReference xmlns:wsu="http://docs.oa
sis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="STRId-18220809">
                  <wsse:KeyIdentifier EncodingType="http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Bas
e64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-
200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier"
>CuJdE1B2dUFd1dkLZSzQ5vj6MYg=</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>
         <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/20
04/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="Timestamp-6400133">
            <wsu:Created>2006-06-22T11:34:04.062Z</wsu:Created>
            <wsu:Expires>2006-06-22T11:39:04.062Z</wsu:Expires>
         </wsu:Timestamp>
         <wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasi
s-open.org/wss/2005/xx/oasis-2005xx-wss-wssecurity-secext-1.1.xsd" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
wssecurity-utility-1.0.xsd" Value="aRI5mvvvXZusAB/5cKCx/fOcW+CDjdk1F3
IcllObVcEOWws9/mV4X2kWEX3hhwK7koX5jMPpl7AtLSbEh8UQGCa8yBua++yveprFl02
0ToVtePVOcWsBLM+9VHu9bJbhvaaps43RiUkym6xvVU/yL3eKTbhdhB/RQDI3kylXda
s=" wsu:Id="SigConf-17122634" />
      </wsse:Security>
   </soapenv:Header>
   <soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/o
asis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-19400027">
      <xenc:EncryptedData Id="EncDataId-19400027" Type=
"http://www.w3.org/2001/04/xmlenc#Content">
         <xenc:EncryptionMethod Algorithm=
              "http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
         <xenc:CipherData>
               <xenc:CipherValue>f6uWHGsYmGwHuno2j4H7a4qCMhPLTlCIg40p
KLciESBzeCT8rvyl+qHXsFkZJq2m4uj9TEFtRX6efQ5MHBEJozMgI03LSVanh6MmHgt5o
ilIJClWcQifEx0Azeo3KWnQKSc9lg0ywhKJH+JVBsPSP7E19jZAsR77wUEBBIprxs5W59
7C/mJh38iXSncwWccE7OCckf1x34FCfKHSqn46MCohZWiPZRjSmAI5dGFMKwttzpmsmXr
LHLVrsjm4w9onis+Xr5gbi3Gcx6P0F2ZJGLBb9bkGh/IvjYutgzRD7zhyRZxUmM/oZTVs
JJ7dA9YOED5l1C64f4yuqR6TtuVw3gIiuspxWafKwlJuuD0/9m6Ri4AvQuOVEioz45MM
5FBCQU+0LFceSlEFFKhN9yLUI9hgLsCYRzc8eedPAhZDjJEDHec5M9LZ0C07sKu7Cvnr
jiino53xZmk5uQHs4JlNoA==</xenc:CipherValue>
         </xenc:CipherData>
      </xenc:EncryptedData>
   </soapenv:Body>
</soapenv:Envelope>

Summary

In order for web services to be truly useful in the enterprise environment, it needs to have the appropriate security capabilities. By combining with technologies such as XML Signature and XML Encryption and providing a standard way of presenting that information, WS-Security makes it possible to protect both incoming and outgoing SOAP messages from several different security threats.

By requiring digital signatures, you can limit access to authorized individuals or organizations, as well as verifying that information has not been altered in transit. By including encryption, you can prevent data from being seen (or at least understood) by unintended recipients. And by adding a Timestamp (and signing it) you can prevent messages from being captured and replayed.

In this tutorial, the staff at the Daily Moon secured the web services they created in earlier parts of this series. Next, in Part 5, they will look at applying security policies to the service.


Download

DescriptionNameSize
Source codesecurity-code-files.zip20KB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into SOA and web services on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=SOA and web services
ArticleID=155478
ArticleTitle=Understanding web services specifications, Part 4: WS-Security
publish-date=08222006