Java Web services: Axis2 WS-Security basics

See how to install Rampart into Axis2 and implement UsernameToken handling

Learn how to add the Rampart security module to Apache Axis2 and start using WS-Security features in your Web services. Dennis Sosnoski resumes his Java Web services series with a look at WS-Security and WS-SecurityPolicy use in Axis2, starting with UsernameToken as a simple first step. The next few columns will take you further with WS-Security and WS-SecurityPolicy, as implemented by Axis2 and Rampart.

Share:

Dennis Sosnoski, Consultant and Trainer, Sosnoski Software Associates Ltd

Author photoDennis Sosnoski is a consultant and trainer specializing in Java-based XML and Web services. His professional software development experience spans more than 30 years, with the last 10 focused on server-side XML and Java technologies. Dennis is the lead developer of the open source JiBX XML Data Binding framework and the associated JiBX/WS Web services framework, as well as a committer on the Apache Axis2 Web services framework. He was also one of the Expert Group members for the JAX-WS 2.0 and JAXB 2.0 specifications. The material for the Java Web Services series is based on Dennis' training classes.



26 May 2009

Also available in Chinese Russian Japanese Vietnamese Spanish

Develop skills on this topic

This content is part of a progressive knowledge path for advancing your skills. See Implementing WS-Security for Java web services

Security is a major requirement of many types of enterprise services. It's also a risky area to try to implement on your own, because even a minor and obscure oversight can lead to serious vulnerabilities. These characteristics make standardization of security handling appealing, allowing many experts to contribute to a standard and avoid any individual's oversights. SOAP-based Web services can use widely supported WS-Security and related standards for their security needs, allowing security to be configured for each service as appropriate.

Apache Axis2 supports these security standards by means of the Rampart module (see Resources). In this article, you'll see how to install, configure, and use Rampart with Axis2 for the basic security function of sending a username and password on a service request. In subsequent columns in this series, you'll learn how to use Rampart for more sophisticated forms of security.

About this series

Web services are a crucial part of Java™ technology's role in enterprise computing. In this series of articles, XML and Web services consultant Dennis Sosnoski covers the major frameworks and technologies that are important to Java developers using Web services. Follow the series to stay informed of the latest developments in the field and be aware of how you can use them to aid your programming projects.

WS-Security

WS-Security is a standard for adding security to SOAP Web service message exchanges (see Resources). It uses a SOAP message-header element to attach the security information to messages, in the form of tokens conveying different types of claims (which can include names, identities, keys, groups, privileges, capabilities, and so on) along with encryption and digital-signature information. WS-Security supports multiple formats for tokens, multiple trust domains, multiple signature formats, and multiple encryption technologies, so in most cases the header information needs to include specific format and algorithm identification for each component. The added information can result in a complex structure for the header information, as shown in the (heavily edited) Listing 1— a sample message with signing and encryption:

Listing 1. Sample message with signing and encryption
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ...>
 <soap:Header>
  <wsse:Security soap:mustUnderstand="1">
   <wsu:Timestamp wsu:Id="Timestamp-d2e3c4aa-da82-4138-973d-66b596d66b2f">
    <wsu:Created>2006-07-11T21:59:32Z</wsu:Created>
    <wsu:Expires>2006-07-12T06:19:32Z</wsu:Expires>
   </wsu:Timestamp>
   <wsse:BinarySecurityToken ValueType="...-x509-token-profile-1.0#X509v3"
     EncodingType="...-wss-soap-message-security-1.0#Base64Binary"
     xmlns:wsu="...oasis-200401-wss-wssecurity-utility-1.0.xsd"
     wsu:Id="SecurityToken-faa295...">MIIEC56MQswCQY...</wsse:BinarySecurityToken>
   <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
    <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
     <wsse:SecurityTokenReference>
      <wsse:KeyIdentifier ValueType=
       "...#X509SubjectKeyIdentifier">LlYsHyhNnOVA9Aj7...</wsse:KeyIdentifier>
     </wsse:SecurityTokenReference>
    </KeyInfo>
    <xenc:CipherData>
     <xenc:CipherValue>g+A2WJhsoGBKUydZ9Za...</xenc:CipherValue>
    </xenc:CipherData>
    <xenc:ReferenceList>
     <xenc:DataReference URI="#EncryptedContent-ba0556c3-d443-4f34-bcd1-14cbc32cd689" />
    </xenc:ReferenceList>
   </xenc:EncryptedKey>
   <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
     <ds:CanonicalizationMethod
       Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"
       xmlns:ds="http://www.w3.org/2000/09/xmldsig#" />
     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
     <Reference URI="#Id-c80f735c-62e9-4001-8094-702a4605e429">
      <Transforms>
       <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>lKjc5nyLQDZAIu/hZb4B6mLquow=</DigestValue>
     </Reference>
     ...
    </SignedInfo>
    <SignatureValue>TiLmWvlz3mswinLVQn58BgYS0368...</SignatureValue>
    <KeyInfo>
     <wsse:SecurityTokenReference>
      <wsse:Reference URI="#SecurityToken-faa295..."
        ValueType="...-x509-token-profile-1.0#X509v3" />
     </wsse:SecurityTokenReference>
    </KeyInfo>
   </Signature>
  </wsse:Security>
 </soap:Header>
 <soap:Body wsu:Id="Id-8db9ff44-7bef-4737-8091-cdac51a34db8">
  <xenc:EncryptedData Id="EncryptedContent-ba05..."
    Type="http://www.w3.org/2001/04/xmlenc#Content"
    xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
   <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
   <xenc:CipherData>
    <xenc:CipherValue>mirmi0KuFEEI56eu2U3cICz...</xenc:CipherValue>
   </xenc:CipherData>
  </xenc:EncryptedData>
 </soap:Body>
</soap:Envelope>

In this article, you'll see some simple examples of WS-Security headers, with only a single token. The next article in the series will go further in discussing the type of complex structure shown in Listing 1.

WS-Security applies to actual SOAP message exchanges. The service implementation can verify that WS-Security has been properly applied to incoming messages, but clients need to know in advance what they must implement in order to use the service. With the complexity of WS-Security and the number of options supported, it can be difficult just to use a text description for this purpose, and manual configuration of WS-Security handling can cause errors. WS-Policy is a general-purpose structure for specifying extension requirements for Web services, and WS-SecurityPolicy is an extension of WS-Policy specifically for WS-Security support. Together these two standards support describing WS-Security requirements in machine-readable form. The WS-Policy and WS-SecurityPolicy information can be used alone or embedded directly inside Web Services Description Language (WSDL) documents, so that Web service frameworks can configure themselves automatically to a service's requirements.


Introducing Rampart

Rampart is the Axis2 security module, supporting WS-Security, WS-SecurityPolicy, WS-SecureConversation, and WS-Trust. In this article, you'll only see Rampart's WS-Security and WS-SecurityPolicy functions; later articles will give you a look at the other features.

Because Rampart is implemented as a module (actually a pair of modules — rampart.mar and rahas.mar), it plugs into the Axis2 processing framework and does its job by intercepting messages at particular points in the inbound and outbound processing, checking or making changes to the messages as appropriate.

Installing Rampart

Rampart comes with several .jar files (in the distribution's lib directory), along with a pair of .mar module files (in the dist directory). You must add the .jar files to your classpath in order to use Rampart with Axis2, and you must add the .mar files to either your classpath or an Axis2 repository structure.

The easiest way of handling the Rampart .jar and .mar files is to add them into your Axis2 installation. You can just directly copy the .jar files from the Rampart lib directory into your Axis2 lib directory, and the .mar files from the Rampart dist directory into your Axis2 repository/modules directory. (You can also use the Ant build.xml in the Rampart samples directory to copy the files across to your Axis2 installation. Just set the AXIS2_HOME environmental variable to your Axis2 installation directory and run ant from a console open to the Rampart sample directory.)

For many WS-Security features, you also need to add the Bouncy Castle security provider to your JVM security configuration and the Bouncy Castle .jar to your Axis2 installation. This step — not needed for the UsernameToken you'll learn about in this article — is required for other security features to be covered later in the series. Because of patent issues with some of the security algorithms, the Bouncy Castle .jar is a separate download from Rampart (see Resources). Download the appropriate version of the .jar for your Java runtime, and add the .jar to the Axis2 lib directory. You then need to modify your Java installation's security policies to use the Bouncy Castle code by adding a line to the java.security file found in your Java runtime's lib/security directory. Look for the section of the file with several different security.provider lines, and add the following line:

security.provider.99=org.bouncycastle.jce.provider.BouncyCastleProvider

The ordering of the security.provider lines in the file doesn't matter, but it's a good idea to add this after the other lines for predefined security provider implementations.

To use the Rampart code in an Axis2 server installation, you need to create a new axis2.war file, one that includes the added Rampart .jar and .mar files. You can use the Ant build.xml provided in the webapp directory to create axis2.war, provided you make one change: delete the line <exclude name="axis2-codegen*.jar"/> near the end of the file. Then open a console to the Axis2 webapp directory and run ant. After the build.xml runs, you can find the created axis2.war Web application in the Axis2 installation dist directory.


A sample application

The application provided in the example code (see Downloads) is based on one I used in "Axis2 Data Binding" to demonstrate data-binding alternatives for Axis2. For this article and the following ones on Axis2 WS-Security support, I've trimmed it down to just three operations: getBook, addBook, and getBooksByType. To keep things simple, only the Axis Data Binding (ADB) version of the code is provided, but this is not a requirement of working with WS-Security in Axis2 — Rampart implements WS-Security at a level that's independent of the data-binding technique your code uses, so it works with all forms of data binding supported by Axis2.

The root directory of the example code is jws04code. Inside this directory, you'll find Ant build.xml and build.properties files, the library.wsdl file giving the service definition for the example application, a log4j.properties file used to configure client-side logging, and several property-definition XML files (all named XXX-policy-client.xml or XXX-policy-server.xml). The build.properties file configures the operation of the example application. Listing 2 shows the supplied version of this properties file:

Listing 2. Supplied build.properties file
# set axis-home to your Axis2 installation directory
axis-home=PATH_TO_AXIS2_INSTALLATION
# set the connection protocol to be used to access services (http or https)
protocol=http
# set the name of the service host
host-name=localhost
# set the port for accessing the services (change this for monitoring)
host-port=8080
# set the base path for accessing all services on the host
base-path=/axis2/services/
# set the name of the policy file to be used by the client
client-policy=plain-policy-client.xml
# set the name of the policy file to be used by the server
server-policy=plain-policy-server.xml

Before trying out the examples, you need to edit the build.properties file and set the actual path to your Axis2 installation (with Rampart added, as discussed in the preceding section). If you're using a different host or port number for your server, you also need to modify the host-name and host-port values. I'll discuss the remaining values later in this article.


Giving WS-Security a try

WS-Security defines several types of security tokens (including tokens that are part of the core specification, and those defined by profiles as plug-in extensions to the specification), with many options for how the tokens are constructed and used. The point of this article is the configuration and use of Rampart with Axis2, so I'll just use the simplest useful token as an example: the UsernameToken, defined by the UsernameToken profile.

UsernameToken WS-SecurityPolicy

The purpose of a UsernameToken is just to convey username and password information as part of the WS-Security headers. The most basic form of UsernameToken sends both the username and password as plain text. This isn't optimal from a security standpoint (though there's nothing wrong with using this approach over secure connections), but it's easy to see what's being sent, making it a useful starting point.

The WS-SecurityPolicy configuration for a UsernameToken sent as text can be as simple as shown in Listing 3. This policy (shown here with one line split in two to fit the page width — not valid for actual use) consists of a standard WS-Policy wrapper (the elements using the wsp prefix) around a WS-SecurityPolicy UsernameToken assertion.

Listing 3. WS-SecurityPolicy for plain-text UsernameToken
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
               ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
        </wsp:Policy>
      </sp:SupportingTokens>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

The UsernameToken in Listing 3 uses an IncludeToken attribute to specify the type of message flow that is to include the token — in this case, all message flows that go from the initiator of a request (that is, the client) to the recipient of a request (the server). You could use other defined values for the IncludeToken attribute to specify other uses of the token, but for a UsernameToken this is generally the only value that makes sense.

Applying the policy

WS-Policy and WS-SecurityPolicy are designed to support embedding within WSDL service definitions. References are used to associate a policy to one or more <wsdl:binding>, <wsdl:binding>/<wsdl:operation>, or <wsdl:message> definitions. Axis2 1.4.X implements preliminary handling for policies embedded in WSDL, but as of Axis2 1.4.1 the implementation is not yet robust. This article instead attaches the policies directly to the client and server in order to be compatible with the 1.4.1 code.

Server-side policy handling

For the server side, you apply a policy by adding it into the services.xml configuration file included in each Axis2 .aar service archive. The policy can be added directly as the child of a <service> element to apply to all operations defined by that service. You also need to add a <module> element to services.xml in order to tell Axis2 that the Rampart module must be included in the configuration for the service. Listing 4 is an edited version of the services.xml used by the example application, with the added module reference and policy information shown in bold:

Listing 4. services.xml with embedded policy
<serviceGroup>
  <service name="library-username">
    <messageReceivers>
      <messageReceiver
          class="com.sosnoski.ws.library.adb.LibraryUsernameMessageReceiverInOut"
          mep="http://www.w3.org/ns/wsdl/in-out"/>
    </messageReceivers>
    <parameter
        name="ServiceClass">com.sosnoski.ws.library.adb.LibraryUsernameImpl</parameter>
    <parameter name="useOriginalwsdl">true</parameter>
    <parameter name="modifyUserWSDLPortAddress">true</parameter>
    <operation mep="http://www.w3.org/ns/wsdl/in-out" name="getBook"
        namespace="http://ws.sosnoski.com/library/wsdl">
      <actionMapping>urn:getBook</actionMapping>
      <outputActionMapping>http://.../getBookResponse</outputActionMapping>
    </operation>
    ...

    <module ref="rampart"/>
    <wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd"
        wsu:Id="UsernameToken">
      <wsp:ExactlyOne>
        <wsp:All>
          <sp:SupportingTokens
              xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
            <wsp:Policy>
              <sp:UsernameToken
                  sp:IncludeToken="http://.../IncludeToken/AlwaysToRecipient">
                <wsp:Policy>
                  <sp:HashPassword/>
                </wsp:Policy>
              </sp:UsernameToken>
            </wsp:Policy>
          </sp:SupportingTokens>

          <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
            <ramp:passwordCallbackClass>...PWCBHandler</ramp:passwordCallbackClass>
          </ramp:RampartConfig>

        </wsp:All>
      </wsp:ExactlyOne>
    </wsp:Policy>
  </service>
</serviceGroup>

Regenerating services.xml the easy way

When you use the Axis2 Wsdl2Java tool to generate server-side deployment files it creates a services.xml file as part of the generated artifacts (in the resources directory, under your generation target directory). Any time your WSDL service definition changes, you must regenerate this file, so the need to embed module reference and policy information in the file can be painful. The example code includes a tool to automate this modification to the generated file: the com.sosnoski.ws.MergeServerPolicy class. (Source and binary are in the mergetool directory.) The build.xml file's generate-server target runs this tool to insert the module reference and appropriate policy information into the generated services.xml file each time the server code is generated. You can use the tool for your own projects if you want. It takes the path to the services.xml file as the first command-line parameter, the path to the policy file as the second, and the names of any modules to be added as the remaining command-line parameters.

If you compare the embedded policy in Listing 4 with the basic policy in Listing 3, you'll see one addition — a <ramp:RampartConfig> element. This element provides Rampart-specific extensions to the policy information, in this case giving the name of a class to be used for handling password callbacks. The callback is how your server code can verify the username-and-password combination supplied by the client on a request.

Listing 5 shows the actual implementation of the callback class, as used for the plain-text password. In this case, both the username and password are supplied to the callback, and all the callback needs to do is verify the combination. If the username and password match the expected values, this just returns; otherwise, it throws an exception to indicate the error.

Listing 5. Password callback code
import org.apache.ws.security.WSPasswordCallback;

public class PWCBHandler implements CallbackHandler
{
    public void handle(Callback[] callbacks)
        throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
            String id = pwcb.getIdentifer();
            if (pwcb.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN) {

                // used when plain-text password in message
                if (!"libuser".equals(id) || !"books".equals(pwcb.getPassword())) {
                    throw new UnsupportedCallbackException(callbacks[i], "check failed");
                }

            }
        }
    }
}

For a real application, you'd naturally want to use some other mechanism (such as a database or an external security mechanism) to verify the username and password combination. The callback technique lets you use any verification technique you want as an extension of the Rampart security handling.

Client-side configuration

To use Rampart for your client code, you first need to have the module available for use with Axis2. You can do this by configuring an Axis2 repository structure for the client, but it's generally easier just to include the rampart.mar module file (and any other modules you need to use) in your classpath. The supplied example uses the classpath approach.

You then need to configure the security policy and any related parameters for the client. The easiest way to handle this configuration is to set values directly on the service stub. Listing 6 shows how the configuration is done in the example code:

Listing 6. Client configuration
    /**
     * Load policy file from classpath.
     */
    private static Policy loadPolicy(String name) throws XMLStreamException {
        ClassLoader loader = WebServiceClient.class.getClassLoader();
        InputStream resource = loader.getResourceAsStream(name);
        StAXOMBuilder builder = new StAXOMBuilder(resource);
        return PolicyEngine.getPolicy(builder.getDocumentElement());
    }

    public static void main(String[] args) throws IOException, XMLStreamException {

        // check for required command line parameters
        if (args.length < 4) {
            System.out.println("Usage:\n  java " +
                "com.sosnoski.ws.library.adb.WebServiceClient protocol host port path");
            System.exit(1);
        }

        // create the client stub
        String target = args[0] + "://" + args[1] + ":" + args[2] + args[3];
        System.out.println("Connecting to " + target);
        LibraryUsernameStub stub = new LibraryUsernameStub(target);

        // configure and engage Rampart
        ServiceClient client = stub._getServiceClient();
        Options options = client.getOptions();
        options.setProperty(RampartMessageData.KEY_RAMPART_POLICY,
            loadPolicy("policy.xml"));
        options.setUserName("libuser");
        options.setPassword("books");
        client.engageModule("rampart");

The configuration portion is the final code block in Listing 6. This gets the org.apache.axis2.client.ServiceClient instance from the created stub and sets the policy information (loaded from the classpath) and username/password in the client options. It then engages the Rampart module in the Axis2 configuration used by the client. Once this is done, you can use the stub to access the service just as you would without WS-Security, and Rampart adds the UsernameToken automatically to each request.

Confirming the results

With Ant installed, you can just run ant from a console open to the example code directory to build both client and server code. You can then deploy the created library-username.aar file to your Axis2 server installation (one that includes the Rampart .jars and .mars, of course), and try out the client by entering ant run at the console. If everything is set up correctly, you should see the output shown in Figure 1:

Figure 1. Console output when running application
Console output when running application

Just running the client with the server doesn't show you what's happening, of course. You can use a tool such as TCPMon to act as an intermediary between the client and server and capture the message exchange to see the WS-Security UsernameToken in action (see Resources). To do this, you'd first need to get TCPMon set up and accepting connections from the client on one port, which it then forwards to the server running on a different port (or a different host). You can then edit the build.properties file and change the host-port value to the listening port for TCPMon. If you again enter ant run at the console, you should then see the messages being exchanged. Listing 7 shows a sample client-message capture:

Listing 7. Client message with UsernameToken
<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse="...wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
          wsu:Id="UsernameToken-1815911473">
        <wsse:Username>libuser</wsse:Username>
        <wsse:Password Type="...wss-username-token-profile-1.0#PasswordText"
            >books</wsse:Password>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:type>scifi</ns2:type>
    </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

Securing UsernameToken

A basic plain-text UsernameToken doesn't provide much security directly, because both the username and the corresponding password are visible to anyone able to monitor a message. If you use an encrypted communication channel, this isn't a real problem — as long as the channel encryption is solid, no outside party can monitor a message. WS-SecurityPolicy conveniently defines a way to require the use of an encrypted channel, as shown in Listing 8 (again with a line split to fit page width — see the example code package's secure-policy-server.xml file for the real policy):

Listing 8. Policy requiring HTTPS connection
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
  "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
 <wsp:ExactlyOne>
  <wsp:All>
   <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
     <wsp:Policy>
      <sp:TransportToken>
        <wsp:Policy>
         <sp:HttpsToken RequireClientCertificate="false"/>
        </wsp:Policy>
      </sp:TransportToken>
     </wsp:Policy>
   </sp:TransportBinding>
   <sp:SupportingTokens
     xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
     <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
          ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"/>
    </wsp:Policy>
   </sp:SupportingTokens>
  </wsp:All>
 </wsp:ExactlyOne>
</wsp:Policy>

The portion of Listing 8 shown in bold is the added part, consisting of a <sp:TransportBinding> element and nested <sp:HttpsToken> element. The <sp:HttpsToken> element says that a secure HTTPS connection must be used in communicating with the service. If you try building the service .aar with this policy (by changing the server-policy value in build.properties to secure-policy-server.xml, and then running ant build-server) and deploying it, you'll see that Rampart enforces this policy requirement, rejecting any normal HTTP connections.

If you want to try out an HTTPS connection to the service you can do so, but you first need to configure your Web server to support HTTPS. (Tomcat has good instructions for this, at /tomcat-docs/ssl-howto.html.) You also need to change the protocol value in build.properties to https, and if you're using a self-signed certificate for the Web server, you need to pass a trust store to the client when running the Ant test target. The supplied build.xml has a commented-out line to do this, so you can just uncomment the line and set the location of the appropriate trust store file on your system.

Another way of making UsernameToken more secure works even over unencrypted links. This method uses a digest value computed over a string made up of two other text values combined with the password. One of the text values, the nonce, is a random value generated by the sender for each request. The other, the created timestamp, is just the time at which the sender created the UsernameToken. Both these values are included in the UsernameToken as plain text. When properly used by both client and server, the combination of these values with the password in the digest makes it possible for the server to verify that the correct password was used when generating the digest, while making it difficult for any outside party to fake a valid password. Listing 9 gives a policy example for using the digest password, followed by an actual capture from a message using the digest password (both reformatted to fit page width — see the hash-policy-client.xml file for the real policy). The differences from the original policy are again shown in bold.

Listing 9. Policy using password digest, and sample message
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:SupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/
ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:HashPassword/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SupportingTokens>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

<?xml version='1.0' encoding='UTF-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <soapenv:Header>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-1.0.xsd"
        soapenv:mustUnderstand="1">
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
          wsu:Id="UsernameToken-1421876889">
        <wsse:Username>libuser</wsse:Username>
        <wsse:Password Type="...wss-username-token-profile-1.0#PasswordDigest"
          >/Wt/2yDdZwa8a5qd7U70hrp29/w=</wsse:Password>
        <wsse:Nonce>4ZQz5ytME/RXfChuKJ03iA==</wsse:Nonce>
        <wsu:Created>2009-03-17T11:20:57.467Z</wsu:Created>
      </wsse:UsernameToken>
    </wsse:Security>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:getBooksByType xmlns:ns2="http://ws.sosnoski.com/library/wsdl">
      <ns2:type>scifi</ns2:type>
    </ns2:getBooksByType>
  </soapenv:Body>
</soapenv:Envelope>

Wrapping up

In this article, you've seen how to use Axis2 and Rampart for a basic form of policy-based WS-Security handling. In the next Java Web services installment, you'll learn about two powerful features of WS-Security: XML encryption and signatures. Using XML encryption lets you keep your message content secret when operating over any type of connection, even when untrusted intermediaries are involved in the processing. Using XML signatures gives you guarantees that messages are really from the claimed originator and that the message content has not been tampered with in transit. Encryption and signing are the basis for most enterprise security implementations, so check back to see how you can apply these features in your own web services.


Download

DescriptionNameSize
Source code for this articlej-jws4.zip10KB

Resources

Learn

Get products and technologies

Discuss

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 Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, SOA and web services
ArticleID=391851
ArticleTitle=Java Web services: Axis2 WS-Security basics
publish-date=05262009