Java Web services: WS-Security with Metro

See how to handle WS-Security with the Metro Web services framework

The Metro Web services stack is based on the reference implementations of the JAXB 2.x and JAX-WS 2.x Java™ standards but also includes support for a full range of WS-* SOAP extension technologies. This article continues Dennis Sosnoski's Java Web services column series with coverage of WS-Security configuration and usage in Metro.

Dennis Sosnoski, Architecture 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.



01 December 2009

Also available in Chinese Russian Japanese Portuguese

As you know from "Introducing Metro," the reference implementations of the JAXB 2.x data-binding and JAX-WS 2.x Web services standards are at the core of the Metro Web services framework. But in and of themselves, JAXB and JAX-WS provide only basic Web services support. JAX-WS doesn't cover the WS-* technologies that upgrade SOAP to work in enterprise environments, so other software components are needed to add support for these technologies.

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 aware of how you can use them to aid your programming projects.

In Metro, the main added component is Web Services Interoperability Technologies (WSIT). WSIT is the current incarnation of what was originally known as Project Tango — Sun's effort to ensure interoperability of WS-* features, including security and reliable messaging, with the Microsoft .NET platform. WSIT provides Metro with support for WS-SecurityPolicy, WS-Trust, WS-SecureConversation, WS-ReliableMessaging, and more. The actual runtime handling of WS-Security is implemented by another added component, the XML and WebServices Security Project (XWSS).

This article shows how to use and configure WS-Security with Metro for stand-alone use as a Web application (outside of the Glassfish server). See Download to get the complete source code for the article's examples, which implement the simple library-management service used previously in this series.

WSIT basics

WSIT is responsible for configuring the Metro runtime to match the WS-Policy specifications for a service, including WS-Policy extensions such as WS-SecurityPolicy. Besides the standard WS-Policy extensions, Metro also uses custom extensions in policy documents to configure user information (such as key store locations and passwords) needed to implement security handling.

WSIT gets the policy information from a Web Services Description Language (WSDL) service description. On the client side, this can be confusing, because the WSDL used for the WSIT configuration is separate from the WSDL used to define the service for JAX-WS. As discussed in "Introducing Metro," the WSDL used to configure the JAX-WS client is obtained either directly from the service or from a location specified when you generate the JAX-WS code. The WSDL that WSIT uses has a fixed file name (though this file can use a <wsdl:import> to reference a separate file with the full WSDL), and is always accessed from the classpath.

On the server side, WSIT requires a WSDL to be provided at a location specified by the WEB-INF/sun-jaxws.xml configuration file (discussed in "Introducing Metro"). The supplied WSDL must include the custom extensions used to configure user information for WSIT, but these custom extensions are deleted from the version of the WSDL provided in response to HTTP GET requests to the service endpoint.

The custom extensions used to configure WSIT user information look the same on the client and server sides but differ in the XML namespace used for the extension elements. On the client, this namespace is http://schemas.sun.com/2006/03/wss/client; on the server the namespace is http://schemas.sun.com/2006/03/wss/server.


UsernameToken in Metro

"Axis2 WS-Security basics" introduced WS-Security in Axis2/Rampart with the simple case of a UsernameToken. UsernameToken provides a standard way of representing a username and password pair with WS-Security. The password information can be sent as plain text (normally, used in production only when combined with Transport Layer Security [TLS] or WS-Security encryption — but convenient for testing) or as a hash value.

To implement a simple plain-text UsernameToken example on Metro, you need to use a WSDL service definition with the appropriate WS-Policy/WS-SecurityPolicy configuration included. Listing 1 shows an edited version of the same basic WSDL service definition used in "Introducing Metro," this time including policy information to require UsernameToken on requests from the client to the server. The policy reference in the <wsdl:binding> is shown in bold, as is the policy itself.

Listing 1. Plain-text UsernameToken WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
    xmlns:wns="http://ws.sosnoski.com/library/wsdl"
    xmlns:tns="http://ws.sosnoski.com/library/types"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    ...
  </wsdl:types>

  <wsdl:message name="getBookRequest">
    <wsdl:part element="wns:getBook" name="parameters"/>
  </wsdl:message>
  ...

  <wsdl:portType name="Library">
    <wsdl:operation name="getBook">
      <wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
      <wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
    </wsdl:operation>
    ...
  </wsdl:portType>

  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
  
    <wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        URI="#UsernameToken"/>

    <wsdlsoap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getBook">
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    ...
  </wsdl:binding>

  <wsdl:service name="MetroLibrary">
    <wsdl:port binding="wns:LibrarySoapBinding" name="library">
      <wsdlsoap:address location="http://localhost:8080/metro-library-username"/>
    </wsdl:port>
  </wsdl:service>
  
  <!-- Policy for Username Token with plaintext password, sent from client to
    server only -->
  <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=".../IncludeToken/AlwaysToRecipient"/>
          </wsp:Policy>
        </sp:SupportingTokens>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</wsdl:definitions>

The Listing 1 WSDL tells anyone who wants to access the service what needs to be done in terms of the security handling. You also need to add WSIT custom extensions to the policy information on both client and server sides with user-configuration details to indicate how the security handling will be implemented. These custom extensions fit into the <wsp:Policy> components of the WSDL. Next I'll show you examples of these extensions for each side.

Client-side usage

On the client side, a file with the (fixed) name of wsit-client.xml is used for the WSIT configuration. This file must reside in a root directory (outside any package) on the classpath, or in a META-INF subdirectory of a directory in the classpath. And wsit-client.xml must be a WSDL document that either provides the full service WSDL directly or references a separate WSDL service definition using a <wsdl:import>. Either way, the WSDL must include both the full WS-Policy/WS-SecurityPolicy requirements and the WSIT configuration extensions.

Listing 2 shows the policy section of the Listing 1 WSDL, with a WSIT custom extension added to configure the client-side UsernameToken support. In this case, that custom extension is the <wssc:CallbackHandlerConfiguration> element and child elements, shown in bold. The two child <wssc:CallbackHandler> elements define callback classes, the first for the username (name="usernameHandler") and the second for the password (name="passwordHandler"). The specified class(es) must implement the javax.security.auth.callback.CallbackHandler interface.

Listing 2. UsernameToken policy with WSIT client-side extensions
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/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=".../IncludeToken/AlwaysToRecipient"/>
        </wsp:Policy>
      </sp:SupportingTokens>
      <wssc:CallbackHandlerConfiguration wspp:visibility="private"
          xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
        <wssc:CallbackHandler name="usernameHandler"
            classname="com.sosnoski.ws.library.metro.UserPassCallbackHandler"/>
        <wssc:CallbackHandler name="passwordHandler"
            classname="com.sosnoski.ws.library.metro.UserPassCallbackHandler"/>
      </wssc:CallbackHandlerConfiguration>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

In Listing 2, both callbacks use the same class. Listing 3 shows the callback-class code, which just checks the type of each callback request and sets the appropriate value:

Listing 3. Client callback code
public class UserPassCallbackHandler implements CallbackHandler
{
    public void handle(Callback[] callbacks) throws UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof NameCallback) {
                ((NameCallback)callbacks[i]).setName("libuser");
            } else if (callbacks[i] instanceof PasswordCallback) {
                ((PasswordCallback)callbacks[i]).setPassword("books".toCharArray());
            } else {
                throw new UnsupportedCallbackException(callbacks[i],
                    "Unsupported callback type");
            }
        }
    }
}

You don't have to use a callback for either the username or the password. If you're using fixed values for these you can instead set them directly in the corresponding <wssc:CallbackHandler> elements by replacing the classname="xxx" attributes with default="yyy" attributes (where the attribute value is the actual username or password).

Server-side usage

On the server side, the WSIT configuration information needs to be present in the WSDL service definition. As discussed in "Introducing Metro," the location of a service WSDL can be specified as a parameter in the WEB-INF/sun-jaxws.xml within the service WAR file. This WSDL is optional if you're not using WSIT features, in which case a WSDL will be generated automatically at run time. If you're using WSIT features, the WSDL is required and must include any custom extension elements necessary to configure WSIT for the features used by the service. Listing 4 shows the policy section of the Listing 1 WSDL, this time with a WSIT custom extension added to configure the server-side UsernameToken support (shown in bold):

Listing 4. UsernameToken policy with WSIT server-side extensions
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
    "http://docs.oasis-open.org/wss/2004/01/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=".../IncludeToken/AlwaysToRecipient"/>
        </wsp:Policy>
      </sp:SupportingTokens>
      <wsss:ValidatorConfiguration wspp:visibility="private"
          xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy">
        <wsss:Validator name="usernameValidator"
            classname="com.sosnoski.ws.library.metro.PasswordValidator"/>
      </wsss:ValidatorConfiguration>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

The server-side WSIT extension in Listing 4 takes the form of a <wsss:ValidatorConfiguration> element and child <wsss:Validator> element, specifying the class to be used as a validator callback. Listing 5 shows the code for this class, which must implement the com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidator interface. In this case, it just checks the supplied username and password against fixed values, but it could easily use a database lookup or other mechanism instead.

Listing 5. Server callback code
public class PasswordValidator implements PasswordValidationCallback.PasswordValidator
{
    public boolean validate(Request request) throws PasswordValidationException {
        PasswordValidationCallback.PlainTextPasswordRequest ptreq 
            = (PasswordValidationCallback.PlainTextPasswordRequest)request;
        return "libuser".equals(ptreq.getUsername()) &&
            "books".equals(ptreq.getPassword());
    }
}

Metro policy tool

Metro/WSIT requires you to add configuration information to your WSDLs, just as with Axis2/Rampart. The earlier articles in this series covering Axis2/Rampart used a special policy tool during the build process to generate modified WSDLs as needed. A similar tool, designed around the needs of Metro/WSIT, is included in the example-code download for this article.

This tool is the com.sosnoski.ws.MergeTool application, in the mergetool directory of the sample code. MergeTool merges data into a target XML document, matching nested XML elements to find the data to be merged and to determine the merge point in the target document. The sample application's build.xml uses MergeTool to add WSIT configuration information for the client or server into the WSDL for the service. You can also use MergeTool in your own applications, if you wish — the mergetool/readme.txt file contains some basic usage information, and you can also see the way it's used in the supplied build.

If you don't supply a <wsss:ValidatorConfiguration>, Metro will use the authorization mechanism supplied by your Web application container (the Web server providing servlet support).

Building and running the sample code

Before you can try out the sample code, you need to download and install a current version of Metro (the code was tested with the 1.5 release) on your system (see Resources). You also need to edit the build.properties file in the root directory of the unzipped sample-code download to change the value of the metro-home property to the path to your Metro installation. If you're going to be testing with a server on a different system or port, you may also want to change the host-name and host-port.

To build the sample application using the supplied Ant build.xml, open a console to the root directory of the download code and type ant. This will first invoke the JAX-WS wsimport tool (included in the Metro distribution), then compile the client and server, and finally package the server code as a WAR (generating separate versions of the service WSDL containing client and server WSIT configuration information in the process). Note that the version of wsimport included in Metro 1.5 will issue a warning message (because of a quirk in the tool's processing of schemas embedded in WSDL): src-resolve: Cannot resolve the name 'tns:BookInformation' to a(n) 'type definition' component.

You can then deploy the generated metro-library.war file to your test server, and finally type ant run on the console to try running the sample client. The sample client runs through a sequence of several requests to the server, printing brief results for each request.


Signing and encrypting in Metro

UsernameToken's simplicity makes it a good starting point, but it isn't a typical use of WS-Security. Most often, you'll use either signatures or encryption, or both. Listing 6 shows an edited example of WSDL using both signatures and encryption (based on an example from "Axis2 WS-Security signing and encryption" — see that article for a more detailed discussion of WS-Security signing and encryption in general). The policy portions of the WSDL are shown in bold.

Listing 6. Signing/encrypting WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
    xmlns:wns="http://ws.sosnoski.com/library/wsdl"
    xmlns:tns="http://ws.sosnoski.com/library/types"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
  <wsdl:types>
    ...
  </wsdl:types>

  <wsdl:message name="getBookRequest">
    <wsdl:part element="wns:getBook" name="parameters"/>
  </wsdl:message>
  ...

  <wsdl:portType name="Library">
    <wsdl:operation name="getBook">
      <wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
      <wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
    </wsdl:operation>
    ...
  </wsdl:portType>

  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
  
    <wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        URI="#SignEncr"/>

    <wsdlsoap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="getBook">
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    ...
  </wsdl:binding>

  <wsdl:service name="MetroLibrary">
    <wsdl:port binding="wns:LibrarySoapBinding" name="library">
      <wsdlsoap:address location="http://localhost:8080/metro-library-username"/>
    </wsdl:port>
  </wsdl:service>
  
  <!-- Policy for first signing and then encrypting all messages, with the certificate
   included in the message from client to server but only a thumbprint on messages from
   the server to the client. -->
  <wsp:Policy wsu:Id="SignEncr" 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:AsymmetricBinding
            xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:InitiatorToken>
              <wsp:Policy>
                <sp:X509Token sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
                  <!-- Added this policy component so Metro would work with the same
                   certificates (and key stores) used in the Axis2/Rampart example. -->
                  <wsp:Policy>
                    <sp:RequireThumbprintReference/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:InitiatorToken>
            <sp:RecipientToken>
              <wsp:Policy>
                <sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
                  <wsp:Policy>
                    <sp:RequireThumbprintReference/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:RecipientToken>
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:TripleDesRsa15/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:Layout>
              <wsp:Policy>
                <sp:Strict/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:OnlySignEntireHeadersAndBody/>
          </wsp:Policy>
        </sp:AsymmetricBinding>
        <sp:SignedParts
            xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
        </sp:SignedParts>
        <sp:EncryptedParts
            xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
        </sp:EncryptedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</wsdl:definitions>

The only significant difference between the Listing 6 WSDL and that used in the earlier Axis2/Rampart example is the addition of a policy to the <sp:InitiatorToken> component to require using a thumbprint reference when the X.509 certificate is not included in a message. This addition is required due to differences in how references are handled by default in Metro and Axis2.

When the client (the initiator, in WS-SecurityPolicy-speak) sends a message, the X.509 certificate for the client is sent as part of the message (because of the sp:IncludeToken=".../IncludeToken/AlwaysToRecipient" attribute on the <sp:InitiatorToken/wsp:Policy/sp:X509Token> element) and used by the server to verify signatures. When the server replies to the client, it needs to reference that same certificate from the client as used in the encryption processing. Axis2/Rampart defaults to using a thumbprint reference for the certificate identification, if no other method is specified. Metro/WSIT defaults to using another method, called subject key identifier (SKI). The certificates used in the Axis2/Rampart example were of a form that did not support SKI, so they won't work with Metro/WSIT by default. Adding the <sp:RequireThumbprintReference/> element to the policy tells Metro/WSIT to use a thumbprint reference instead for the certificate.

This change to the policy allows the same certificates and key stores used in the earlier Axis2/Rampart example to be used for this example. That in turn allows the Axis2/Rampart client example to be used with the Metro/WSIT server, and vice versa, as a convenient way of checking interoperability. If you try this out (which you can do by changing the target path passed to the test client in each case) you'll find that for the most part the messages are exchanged without difficulty — but with one difference in operation, discussed in the Interoperability issue section, below.

As with the UsernameToken example, WSIT needs custom extensions to the policy information on both client and server sides to provide additional configuration details.

Client-side usage

Listing 7 shows the WSIT custom extensions added to the WSDL policy to configure the client-side handling for the example. These custom extensions, shown in bold, configure the key store (containing the client's private key and corresponding certificate) and the trust store (containing the server's certificate) needed for the signing and encryption.

Listing 7. Signing and encrypting policy with WSIT client-side extensions
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="SignEncr">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding xmlns:sp=
      "http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          ...
        </wsp:Policy>
      </sp:AsymmetricBinding>
      <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <sp:Body/>
      </sp:SignedParts>
      <sp:EncryptedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <sp:Body/>
      </sp:EncryptedParts>
    
      <wssc:KeyStore alias="clientkey" keypass="clientpass"
          location="client.keystore" storepass="nosecret"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
          xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"/>
      <wssc:TrustStore location="client.keystore" peeralias="serverkey"
          storepass="nosecret" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy"
          wspp:visibility="private"
          xmlns:wssc="http://schemas.sun.com/2006/03/wss/client"/>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

The Listing 7 WSIT custom extensions give all the necessary parameters for accessing the key store and trust store (which in this case are the same file), including the password required for accessing the client's private key (the keypass="clientpass" attribute on the <wssc:KeyStore> element). It's also possible to use a callback for password information, as you'll see in the next section.

The named key store and trust store must be in a META-INF child directory of a directory in the classpath. You can also use absolute file paths for these files — rather than just a file name — which lets you locate them at any fixed location on your file system. (Recall that for the client, the WSDL including the WSIT custom extensions must use the fixed name wsit-client.xml and must be either in a root directory of the classpath, or in a META-INF child directory of a root directory in the classpath.)

Server-side usage

The server-side WSIT custom extensions added to the WSDL are shown in Listing 8 (again in bold). In this case the <wsss:KeyStore>'s keypass attribute gives a class name rather than an actual password value (as in the Listing 7 client-side example). When you use this approach, the referenced class must implement the javax.security.auth.callback.CallbackHandler interface, and it will be called by the WSIT code when it needs access to the password for the secret key. You can also use this same technique of specifying a class name rather than a password value for the storepass values.

Listing 8. Signing and encrypting policy with WSIT server-side extensions
<wsp:Policy xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsu=
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
wsu:Id="SignEncr">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding xmlns:sp=
      "http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          ...
        </wsp:Policy>
      </sp:AsymmetricBinding>
      <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <sp:Body/>
      </sp:SignedParts>
      <sp:EncryptedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <sp:Body/>
      </sp:EncryptedParts>
    
      <wsss:KeyStore alias="serverkey"
          keypass="com.sosnoski.ws.library.metro.KeystoreAccess"
          location="server.keystore" storepass="nosecret"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
          xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"/>
      <wsss:TrustStore location="server.keystore" storepass="nosecret"
          xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private"
          xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"/>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

Listing 9 shows the implementation of the CallbackHandler interface used for this example:

Listing 9. Server key-store password callback code
public class KeystoreAccess implements CallbackHandler
{
    public void handle(
       Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            Callback callback = callbacks[i];
            if (callback instanceof PasswordCallback) {
                ((PasswordCallback)callback).setPassword("serverpass".toCharArray());
            } else {
                throw new UnsupportedCallbackException(callback, "unknown callback");
            }
        }
    }
}

Building and running the sample code

The signing and encrypting example uses the same build steps as the UsernameToken example, except that you must change the build.properties file to use variant-name=signencr (rather than the value username for the UsernameToken example).

Interoperability issue

If you try using the Axis2/Rampart client with the Metro/WSIT server (or vice versa) you may run into a problem when the client tries to add a book with a duplicate International Standard Book Number (ISBN). In this case the service returns a Fault, rather than a normal SOAP response message. The Axis2/Rampart 1.5.x releases correctly perform the usual signature and encryption handling required by the WSDL in this case, but Metro/WSIT 1.5 does not, resulting in a failure on the client. This is an error in the WSIT code, which should be corrected for the next Metro release.

If you run the test with an earlier version of Axis2/Rampart, you probably won't see any problems — because Rampart had the same bug up until the Rampart 1.5 release.


Next stop on the Metro

Metro's WSIT support for WS-SecurityPolicy allows both direct configuration of parameters such as usernames and passwords (including key store and private-key passwords) and the use of callbacks to get these values as needed. It also lets you choose between the servlet container's authorization handling and your own callback for verifying username and password combinations on the server. This flexibility allows Metro to meet the needs of many types of applications easily. It's also convenient that Metro comes with the WSIT/XWSS WS-Security support as integrated components, rather than a separate component (with its own release cycles, and generally incompatibilities between different versions of the core component) as with Axis2 and Rampart.

On the downside, information is sparse on using Metro/WSIT stand-alone and configuring it directly (as opposed to using it in combination with the NetBeans IDE and Glassfish application server). Many of the necessary options are documented only in blog postings or e-mail exchanges (see Resources).

The next Java Web services installment continues looking at Metro, this time with a focus on performance. See how Metro performance compares to Axis2, both for simple message exchanges and with WS-Security in use.


Download

DescriptionNameSize
Source code for this articlej-jws10.zip38KB

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=451498
ArticleTitle=Java Web services: WS-Security with Metro
publish-date=12012009