Java web services: Understanding WS-Policy

Learn the details of WS-Policy, and see which parts work with three open source Java web services stacks

WS-Policy provides a general structure for configuring features and options that apply to a web service. You've seen it used for WS-Security configurations in this series, and perhaps elsewhere for other extension technologies such as WS-ReliableMessaging. In this article, you'll learn about the structure of WS-Policy documents and the ways you can attach policies to services in Web Service Description Language (WSDL), with security-configuration examples tried on Apache Axis2, Metro, and Apache CXF.

Share:

Dennis Sosnoski, Architecture Consultant and Trainer, Sosnoski Software Solutions, Inc.

Author photoDennis Sosnoski is a consultant and trainer specializing in Java-based SOA 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's SOA and web services training classes.



02 November 2010

Also available in Chinese Russian Japanese Vietnamese Portuguese

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.

You've seen many examples of WS-Policy and WS-SecurityPolicy in the Java web services series, but so far without any discussion of how WS-Policy actually works (or, at least, is intended to work). In this article, I'll first fill in the gaps by giving you a little more background on WS-Policy. Then you'll see how to attach policies to services in WSDL documents. Finally, I'll try some WS-Policy configuration examples for Axis2, Metro, and CXF and tell you how they work in practice. (See Download to get the full sample code.)

WS-Policy basics

WS-Policy defines a simple XML structure consisting of four different elements and a pair of attributes. These elements and attributes, as interpreted by WS-Policy, provide a way to organize and combine policy assertions of any level of complexity. To define the actual assertions that make up a policy, you use domain-specific extensions such as WS-SecurityPolicy, rather than WS-Policy per se.

WS-Policy versions

The WS-Policy details in this article are specific to the "official" WS-Policy 1.5 published by the W3C, but the same general rules apply to the older "submission" version still in widespread use. As with other WS-* technologies, you can tell which version a document uses by checking the XML namespace. The namespace for WS-Policy 1.5 is http://www.w3.org/ns/ws-policy; for the submission version, it's http://schemas.xmlsoap.org/ws/2004/09/policy. Throughout this article, I use the http://www.w3.org/ns/ws-policy namespace, represented by the wsp prefix.

For convenience, WS-Policy defines both a normal-form expression of a policy and a set of rules you can use to create more-compact policy expressions. The normal form can be somewhat verbose, so (despite the WS-Policy recommendation stating that "the normal form of a policy expression SHOULD be used where practical") most writers of policy documents tend to use at least some portions of the compact-expression rules to make the documents more human-friendly. The interpretation of policy documents is based on the normal form, though, so that's what I'll cover first.

Normal-form expression

The normal-form policy expression uses three elements at most, which must always be nested in a particular order. The outermost element is always <wsp:Policy>, and it must contain a single <wsp:ExactlyOne> child element. The nested <wsp:ExactlyOne> in turn contains any number (possibly zero) of <wsp:All> child elements. So the simplest possible normal-form policy expression is <wsp:Policy><wsp:ExactlyOne/></wsp:Policy>.

Any policy assertions in the normal form must be nested within a <wsp:All> element. These policy assertions can themselves contain policy expressions. You've seen this in past articles of this series, where many of the WS-SecurityPolicy assertions contain nested policy expressions. In a normal-form policy expression, all these nested policy assertions must themselves also be in normal form. (Actually, they must be in an even-more restrictive subset of normal form, wherein each <wsp:ExactlyOne> element except for the topmost one has one and only one <wsp:All> child element.) Listing 1 shows an excerpt with several examples of nested policy expressions, expressed in normal form:

Listing 1. WS-SecurityPolicy excerpt with nested policy expressions
<wsp:Policy>
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:AsymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
        <wsp:Policy>
          <wsp:ExactlyOne>
            <wsp:All>
              <sp:InitiatorToken>
                <wsp:Policy>
                  <wsp:ExactlyOne>
                    <wsp:All>
                      <sp:X509Token
                          sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                          <wsp:ExactlyOne>
                            <wsp:All>
                              <sp:RequireThumbprintReference/>
                            </wsp:All>
                          </wsp:ExactlyOne>
                        </wsp:Policy>
                      </sp:X509Token>
                    </wsp:All>
                  </wsp:ExactlyOne>
                </wsp:Policy>
              </sp:InitiatorToken>
              ...

Despite the many layers of nested elements, the semantics of this structure is simple. In the normal-form expression of a policy, <wsp:Policy> is just a wrapper for the policy expression, and, in the case of top-level policy expressions, a place to attach a name or identifier to the policy. The nested <wsp:ExactlyOne> element represents an or combination of the alternatives represented by nested <wsp:All> elements (so the whole policy expression is satisfied if any one of the nested alternatives is satisfied). Each <wsp:All> element represents an and combination of the nested policy assertions (so that alternative is satisfied only if all the assertions are satisfied).

Unnormalized policy

Policy expressions don't need to be in normal form. Nonnormal policy expressions can include nested alternatives (multiple <wsp:All> child elements of a <wsp:ExactlyOne> element below the top level) and can also make use of the compact policy expression options discussed in the next section.

If you've studied logic theory, you might recognize the normal-form representation (with no nested alternatives) as equivalent to the disjunctive normal form of a logic expression. Policy expressions really are just logic expressions using a pointy-bracket format, with assertions as clauses. Logic theory shows that any logic expression can be converted to the disjunctive normal form, and the same principle applies to policy expressions written with nested alternatives — they can be expanded into a normal-form representation with alternatives only at the top level. The main advantage of the normal-form expression of policy is that it makes it easy to check two policies for compatibility programatically — if the two normal-form policies are compatible, they'll have one or more one top-level <wsp:All> elements containing the same sets of assertions.

Compact policy expression

The normal-form expression of a policy can be lengthy, especially if it involves nested alternatives. WS-Policy defines options you can use to create policy expressions that are more concise than the normal form permits, making the policies easier for humans to understand. The WS-Policy documentation is confusing in sometimes referring to policies using these options as being in compact form. Really, many compact expressions of a policy can be equivalent to a single normal-form expression. In this article, I'll just use compact expression to refer to policies using one or more of these options.

One feature of compact-expression options is the ability to express policies through nesting of the basic policy elements (called operators in policy terms, because each element implies a particular interpretation of nested assertions) in any order. The nesting rules also define an interpretation of the <wsp:Policy> element used directly (without the single <wsp:ExactlyOne> child element required in the normal form) as equivalent to a <wsp:All>, which is probably the most widely used compact-expression feature.

Listing 2 shows a compact expression of the same policy shown in Listing 1, using this <wsp:Policy> representation. This version is less than half the length of the first one, and for most people would be much easier to understand.

Listing 2. Simple policy in compact form
<wsp:Policy>
  <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">
            <wsp:Policy>
              <sp:RequireThumbprintReference/>
            </wsp:Policy>
          </sp:X509Token>

        </wsp:Policy>
      </sp:InitiatorToken>
      ...

WS-Policy defines a set of transformations you can apply to convert policy expressions using the compact options into normal form, so there's little reason to use normal form directly. It's much easier for computers to transform compact expressions into normal form than it is for humans to interpret normal form.

Policy inclusion

Besides simplifying element nesting, compact expression also provides a way to reference and reuse policy expressions. You do this with the fourth WS-Policy element, <wsp:PolicyReference>. A <wsp:PolicyReference> element can appear anywhere a policy assertion can appear. The referenced policy expression is effectively substituted for the policy reference (technically with an <wsp:All> element replacing the referenced <wsp:Policy> element). This substitution approach is called policy inclusion.

Listing 3 illustrates the use of policy inclusion, showing the Listing 2 policy expression refactored to a form using a separate policy expression and a reference:

Listing 3. Policy reference
<!-- Client X.509 token policy assertion. -->
<wsp:Policy wsu:Id="ClientX509"
    xmlns:wsu="http://.../oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <sp:InitiatorToken>
    <wsp:Policy>
      <sp:X509Token
          sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
        <wsp:Policy>
          <sp:RequireThumbprintReference/>
        </wsp:Policy>
      </sp:X509Token>
    </wsp:Policy>
  </sp:InitiatorToken>
</wsp:Policy>

<wsp:Policy>
  <sp:AsymmetricBinding
      xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
    <wsp:Policy>
      <wsp:PolicyReference URI="#ClientX509"/>
      ...

Policy references can be used both for local policy expressions, as shown in Listing 3, and for external policy expressions. For external policy expressions, the reference's URI attribute normally gives the actual URL of the external policy.

As you'll see in the policy test examples supplied later in this article, policy inclusion is not universally supported at present. This limits the usefulness of this otherwise nice feature.

Policy alternatives

As you saw earlier, WS-Policy's structure supports choices among alternatives as part of a policy, through the <wsp:ExactlyOne> element. With compact expression, you can also (at least in theory) use special attributes to create choices. According to the WS-Policy recommendation, you can add the wsp:Optional="true" attribute to any policy assertion to make that assertion an option rather than a requirement, even when the assertion is a child of a <wsp:All> or <wsp:Policy> element.

Policy alternatives seem like a potentially useful feature, but it's difficult to come up with a nontrivial working example. The cases where this feature is used in practice are generally for making a particular component of the security processing, such as a UsernameToken, optional. More-complex alternatives, such as allowing a client to provide identification in the form of either a UsernameToken or an X.509 certificate, appear to be beyond the capability of current WS-SecurityPolicy implementations.


Policy attachment

In WSDL 1.1 (somewhat dated, but still the most widely used form of service definition), service definitions use a hierarchical structure. The first (bottom) layer consists of <wsdl:message> elements defining the XML structure of messages to and from the service. The second layer is <wsdl:portType> elements defining sets of operations, with each operation specified by input, output, or fault messages. The third layer is <wsdl:binding> elements, which associate a particular message protocol (such as SOAP) and access method with a <wsdl:portType>. The fourth layer is the service-endpoint definitions in the form of <wsdl:port> elements, which specify the address at which a <wsdl:binding> can be accessed.

WSDL schema(s)

WSDL 1.1 has had a long and varied history when it comes to XML schema definitions. The original WSDL 1.1 submission included both a text description of how WSDL XML documents were to be structured and an XML schema definition. Unfortunately, the supplied XML schema didn't match the text. This was corrected in a modified version of the schema somewhat later, but the WSDL 1.1 document was not updated to reflect this change. Then the WS-I Basic Profile group decided to make even more changes to the WSDL schema, so it created what appears to be the best-practices version of this slippery schema. Documents written to one version of the schema are generally not compatible with other versions (despite using the same exact namespace), but fortunately most web services tools basically ignore the schema and accept anything that looks reasonable. See Resources for links to the many schemas of WSDL.

WS-Policy allows you to attach polices to WSDL service definitions at several different points that don't exactly match these layers of definition. Whereas the layers represent a logical structure for the service definitions, WS-Policy is more concerned with messages and groupings of messages. The four levels of message groupings WS-Policy uses are:

  • Message: Policy applies to a particular message (anywhere that message is used if the policy is attached through the <wsdl:message> element, or when used by a particular operation if attached through the input/output/fault definitions of the operation in either the <wsdl:portType> or the <wsdl:binding> element).
  • Operation: Policy applies to all message exchanges for a particular operation (policy attached through the <wsdl:operation> element, within either the <wsdl:binding> or <wsdl:portType>).
  • Endpoint: Policy applies to all message exchanges for a particular service binding (policy attached through <wsdl:port> or <wsdl:binding>) or for all service bindings based on a particular port type (policy attached to that <wsdl:portType>).
  • Service: Policy applies to all endpoints and all operations associated with a service (policy attached at the <wsdl:service> element).

The main policy-attachment mechanism used for WSDL is the same as that used to reference one policy within another policy — the <wsp:PolicyReference> element discussed in the Policy inclusion section. This WS-Policy element can be added as a child of any the previously listed WSDL elements to specify the policy to be applied at that level of message groupings. You can also embed a policy directly as a <wsp:Policy> element with any appropriate content, but it's generally better to use references so the WSDL structure stays clean.

Policies applied at one level of the message groupings are inherited by lower layers, combined within a <wsp:All> element. This makes the actual (or effective, in WS-Policy terms) policy applied to each message the conjunction of all policies applied at the message, operation, endpoint, and service layers. So policy is determined not just by the message itself, but also by the context in which the message is used.

Listing 4 illustrates how this operates, showing a skeleton WSDL definition with policy references:

Listing 4. Policy-attachment example
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">

  <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="#UsernameToken"/>

  <wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
  
  <wsdl:operation name="addBook">
  
    <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="#AsymmEncr"/>


    ...

  </wsdl:operation>

</wsdl:binding>

In this case, a policy requiring a UsernameToken is attached at the <wsdl:binding> level, and an additional policy requiring asymmetric message encryption is attached to the addBook operation defined as part of that binding. Assuming this example shows the full set of policy references for the WSDL, the UsernameToken is always required, but message signing is used only for the addBook operation.

As an alternative to using <wsp:PolicyReference> to reference policies directly from WSDL elements, you can use the wsp:PolicyURIs attribute. You can add this attribute to any WSDL element to which a policy can be attached. It functions in essentially the same way as using <wsp:PolicyReference> child elements.

WS-SecurityPolicy attachment

WS-SecurityPolicy specifies the message-grouping levels at which different types of policy assertions can be attached to a service description. For instance, the <sp:TransportBinding> assertion used to specify transport security can only be attached at the endpoint level, whereas the <sp:AsymmetricBinding> and <sp:SymmetricBinding> assertions used to specify message encryption or signing can only be used at the endpoint or operation level.

Even though the <sp:AsymmetricBinding> or <sp:SymmetricBinding> cannot be specified at the message level, you can specify the message components to be encrypted or signed at the message level. This means that it's at least theoretically possible to specify encryption or signing on a per-message basis.


Policy examples

When this article was originally published, the Axis2 example was not working. Shortly after publication, I was able to resolve the issue by using a different form of configuration. The revised article text and the revised download code reflect this change.

Now that you've learned the principles of WS-Policy and how it works with WSDL, it's time to try some policy examples making use of these principles. As with earlier articles, I tried the code for this one with all three of the main Java open source web services stacks: Axis2, Metro, and CXF.

Listing 5 shows one example (effective1.wsdl in the sample code download) using three levels of policy attachment within a WSDL service definition. The three policies used are:

  • UsernameToken: Require a UsernameToken with hashed password.
  • SymmEncr: Require symmetric encryption using a client-generated secret key.
  • EncrBody: Require encryption of the message body.
Listing 5. Effective-policy example
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"...>
  

  <wsp:Policy wsu:Id="UsernameToken" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:SupportingTokens>
      <wsp:Policy>
        <sp:UsernameToken sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
          <wsp:Policy>
            <sp:HashPassword/>
          </wsp:Policy>
        </sp:UsernameToken>
      </wsp:Policy>
    </sp:SupportingTokens>
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="SymmEncr" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:SymmetricBinding>
      <wsp:Policy>
        <sp:ProtectionToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:ProtectionToken>
        ...
      </wsp:Policy>
    </sp:SymmetricBinding>
    ...
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="EncrBody" xmlns:wsp="http://www.w3.org/ns/ws-policy"...>
    <sp:EncryptedParts>
      <sp:Body/>
    </sp:EncryptedParts>

  </wsp:Policy>
  ...
  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
    <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
        URI="#UsernameToken"/>
    ...
    <wsdl:operation name="getBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>

      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getBooksByType">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:getBooksByType"/>
      <wsdl:input name="getBooksByTypeRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBooksByTypeResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getTypes">
    ...
    </wsdl:operation>

    <wsdl:operation name="addBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#SymmEncr"/>
      <wsdlsoap:operation soapAction="urn:addBook"/>
      <wsdl:input name="addBookRequest">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="addBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="addDuplicateFault">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#EncrBody"/>
        <wsdlsoap:fault name="addDuplicateFault" use="literal"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  ...
</wsdl:definitions>

The policy references (shown in bold) in the Listing 5 WSDL document attach the UsernameToken policy to the <wsdl:binding>, so that the UsernameToken is required for all operations. The SymmEncr policy is attached to the individual <wsdl:operation> for all operations that exchange book information, and the EncrBody policy is attached to the messages that include book information — so that the book information is always sent in encrypted form.

This is a tricky policy, in that it requires the client to generate a secret key and send it to the server with the request message, even though the secret key is only used for encrypting the response. Axis2 1.5.1 (the 1.5.2 distribution was tried, but is missing a file required for the security handling) completely ignored the policy in both the generated code and the server operation, happily running without any security. When I changed the policies to use the older submission namespace Axis2 recognized the policies and ran correctly, except in handling the addBook operation fault response. The returned application-fault response is supposed to use encryption, according to the policy, but Axis2 sent it back unencrypted.

Metro generated a request message with a UsernameToken, but no secret-key information, a complete failure on the first message exchange. CXF 2.3.0 did much better than Metro, handling the policy correctly except in two cases. When the addBook operation succeeds, the response message does not use encryption. The CXF server handled this correctly, but the client threw an exception while processing the response. The other CXF error was the same as Axis2, not using encryption for the application fault response.

The Listing 5 policy demonstrates selective use of message encryption, encrypting only those messages that include book information. However, this policy uses symmetric encryption. It'd be great to be able to do the same type of thing using asymmetric encryption, where the client has its own certificate (especially when you want to sign messages for sender verification). Listing 6 shows an example designed for this purpose (effective2.wsdl in the download). This one uses only two policies from the WSDL:

  • AsymmBinding: Require asymmetric encryption using dual certificates.
  • SignBody: Require signing of the message body.
Listing 6. Asymmetric-signing example
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"...>

  <wsp:Policy wsu:Id="AsymmBinding" xmlns:wsp="http://www.w3.org/ns/ws-policy" ...>
    <sp:AsymmetricBinding>
      <wsp:Policy>
        <sp:InitiatorToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/AlwaysToRecipient">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:InitiatorToken>
        <sp:RecipientToken>
          <wsp:Policy>
            <sp:X509Token sp:IncludeToken=".../IncludeToken/Never">
              ...
            </sp:X509Token>
          </wsp:Policy>
        </sp:RecipientToken>
        ...
      </wsp:Policy>
    </sp:AsymmetricBinding>
  </wsp:Policy>
  
  <wsp:Policy wsu:Id="SignBody" xmlns:wsp="http://www.w3.org/ns/ws-policy" ...>
    <sp:SignedParts>
      <sp:Body/>
    </sp:SignedParts>
  </wsp:Policy>
  ...
  <wsdl:binding name="LibrarySoapBinding" type="wns:Library">
    ...
    <wsdl:operation name="getBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:getBook"/>
      <wsdl:input name="getBookRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="getBookResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getBooksByType">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:getBooksByType"/>
      <wsdl:input name="getBooksByTypeRequest">
        <wsdlsoap:body use="literal"/>
      </wsdl:input>

      <wsdl:output name="getBooksByTypeResponse">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

    <wsdl:operation name="getTypes">
      ...
    </wsdl:operation>

    <wsdl:operation name="addBook">
      <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
          URI="#AsymmBinding"/>
      <wsdlsoap:operation soapAction="urn:addBook"/>
      <wsdl:input name="addBookRequest">
        <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy"
            URI="#SignBody"/>
        <wsdlsoap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="addBookResponse">
        <wsdlsoap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="addDuplicateFault">
        <wsdlsoap:fault name="addDuplicateFault" use="literal"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  ...
</wsdl:definitions>

The Listing 6 example uses asymmetric encryption to sign all the messages providing book information. This means the getBook and getBooksByType response messages should be signed by the server, whereas the addBook request message should be signed by the client. Because this is using asymmetric encryption, where each side has its own certificate and private key, it should be somewhat simpler to handle than the Listing 5 symmetric-encryption example.

External policy references

External policy references don't fit well into the structure of the supplied examples, but I did try them out. For my test, I used both relative references, of the form <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="./asymm-binding-policy.xml"/>, and absolute URLs hosted on a web server. Both Axis2 and Metro were unable to resolve policy references of this type. They worked correctly on CXF.

Axis2 failed in the same way as in the earlier example, completely ignoring the policy components using the WS-Policy 1.5 policy namespaces. When I changed to the submission namespace, Axis2 was able to handle this example without any errors. Because of these problems in using the WS-Policy 1.5 namespace with Axis2, the Axis2 examples in the code download all use the submission namespace.

Metro is unable to work with this policy configuration as supplied, throwing a NullPointerException on the client with the very first request. After some investigation, I found that the problem went away if I attached a policy at the endpoint level, rather than only at the operation and message levels. The Metro example includes an effective3.wsdl with the #AsymmBinding policy referenced only from the <wsdl:binding>, and this example runs without a problem (though, like CXF in the symmetric case, Metro does not apply security to the application-fault response).

CXF also fails with the Listing 6 policy configuration, but without any easy workaround in the current code. The CXF client code incorrectly generates a signature when sending the getBook request message, and the server code then fails in processing the request message. So it looks like the current CXF code insists on generating a signature when an AsymmetricBinding is in scope, even when nothing is being signed.


Policy wrap-up

WS-Policy defines a flexible and powerful structure for expressing constraints of any form. Unfortunately, the implementations of WS-Policy and WS-SecurityPolicy processing used by web services stacks don't implement much of the flexibility. Because of this lack of implementation support, many otherwise useful features of WS-Policy cannot be used for web services intended to interoperate with a full range of web service stacks.

Basic effective-policy processing, whereby policies are attached at different points in WSDL service definitions, is a core feature of the policy and WSDL design and should be used where appropriate for your services. But one of the potentially useful features of this type of configuration — the ability to sign and encrypt messages selectively on an individual basis — does not work reliably (with only Apache Axis2 handling the test cases correctly, and then only after changing the policy namespace). In view of this limitation, it's probably best to stay with policy attachments at the <wsdl:binding> and <wsdl:operation> levels for now if you want best interoperability.

External policies can be especially useful for SOA-type environments, where a set of common policies can be set up for use throughout the organization and each service can reference the policies appropriate to its needs. Even though this feature is not supported at present by all the open source Java web services stacks (with only Apache CXF handling it properly), larger organizations may wish to make use of the feature anyway and restrict web service implementations to using one of the stacks (whether open source or commercial) that supports it. You may also be able to get the same effect by other means, such as by the use of WSDL includes.

In the next article of the series, I'll summarize the performance and interoperability issues with the three main Java web services stacks and give an overview of how these stacks compare for use in implementing secure web services. If you're using secure web services in your organization, you won't want to miss this.


Download

DescriptionNameSize
Sample code for this articlej-jws18.zip94KB

Resources

Learn

Discuss

  • Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

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, Open source
ArticleID=559718
ArticleTitle=Java web services: Understanding WS-Policy
publish-date=11022010