In simple Web service environments, clients connect directly to servers, and the servers directly perform all the necessary processing for the request. As you learned in the last article of this series, SSL-secured connections can provide excellent security for most purposes in this type of environment. But more complex environments are increasingly common, where multiple layers of servers are involved in processing a request. The whole idea of service orchestration, increasingly popular in many enterprise environments, is based on this approach, as is the concept of service-oriented architecture (SOA). In these types of environments, the more powerful alternative of WS-Security is necessary.
WS-Security comes with a heavy performance cost, as discussed in the last article. One way of reducing that cost is to set the WS-SecurityPolicy appropriate for each individual operation or even message defined by a service, rather than applying a single WS-SecurityPolicy to the entire service. Granular use of WS-Security requires more consideration than the one-size-fits-all approach, but when properly applied it can reduce the performance overhead for commonly used operations without weakening the security of operations that need it.
The sample application used for this article is the same one used in "Axis2 WS-Security basics" and "Axis2 WS-Security signing and encryption" — a simple library-management service. (See Download to get the full source code for this article.) This service defines three operations:
getBookto retrieve the details for a particular book identified by International Standard Book Number (ISBN).getBooksByTypeto retrieve the details for all books of a particular type.addBookto add a new book to the library.
To give some interesting variety in the security usage, this article assumes that:
- The
getBookoperation can safely be exposed to anyone (no security). - The
getBooksByTypeneeds authorization (so requires aUsernameToken). - The
addBookoperation needs an audit trail to track who added each book (implemented by signing of the request messages).
In the earlier articles, you saw how to configure Axis2/Rampart by attaching a WS-SecurityPolicy document to the org.apache.axis2.client.ServiceClient instance (on the client side) or by embedding the policy document in the services.xml service configuration (on the server side). This approach works and can be useful in testing, but for production use WS-SecurityPolicy is best associated directly with a service definition by being embedded within a WSDL document. WS-Policy and WS-SecurityPolicy are designed to support this type of embedding, with references from <wsdl:binding>, <wsdl:binding>/<wsdl:operation>, or <wsdl:binding>/<wsdl:operation>/<wsdl:message> definitions used to identify the appropriate policy to be applied to that binding, operation, or message. Axis2 1.4.1 implemented preliminary handling for policies embedded in WSDL, and the implementation has improved in the current Axis2 1.5 release code. To demonstrate the use of policy in WSDL, this article uses the Axis2 1.5 release code in combination with the as-yet unreleased current Rampart code (which should eventually be released as Rampart 1.5).
Listing 1 shows the WSDL for the example application with policy added and referenced from the appropriate locations. (Listing 1 is edited for length and width; the full WSDL is available as library.wsdl in the code download.) Each policy defines an Id value that is then referenced from the appropriate operation (in the case of the UsernameToken policy) or message (in the case of the signing policy), all as shown in bold.
Listing 1. WSDL with granular security policies
<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/">
<!-- Policy for signing message, with certificate from client included in each
message to server -->
<wsp:Policy wsu:Id="SignOnly" 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"/>
</wsp:Policy>
</sp:InitiatorToken>
...
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<!-- Policy for UsernameToken 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:binding name="LibrarySoapBinding" type="wns:Library">
<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:operation name="getBooksByType">
<wsp:PolicyReference
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
URI="#UsernameToken"/>
<wsdlsoap:operation soapAction="urn:getBooksByType"/>
<wsdl:input name="getBooksByTypeRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBooksByTypeResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="addBook">
<wsdlsoap:operation soapAction="urn:addBook"/>
<wsdl:input name="addBookRequest">
<wsp:PolicyReference
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
URI="#SignOnly"/>
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="addBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="library-granular">
...
</wsdl:service>
</wsdl:definitions> |
The Listing 1 policies and WSDL are all taken from the earlier articles, though not previously merged in this way. You might notice one significant difference in the policies, though: the previous versions all included Rampart configuration information, which was specific to either the client or the server. Now that the policy is embedded into the WSDL, it's not practical to include the Rampart configuration directly. (You'd need to edit the WSDL to include your client Rampart configuration information and regenerate code every time this changed, and on the server your Rampart configuration would be exposed to anyone accessing the WSDL.) So the example code instead sets this configuration information separately. To do this, it uses variations of the same techniques previously used for the policies with Rampart configuration included.
Generating code from WSDL works the same from the user perspective whether WS-Policy is included or not. If you look inside the client stub generated from a WSDL containing WS-Policy, you'll see that the policy is attached directly to the components of the service description as it is being constructed, but this is hidden inside the implementation and does not affect the interface methods that your client code uses.
To make use of the WS-SecurityPolicy configuration on the client, you do need to
take some action in your client code. At a minimum, you must engage the Rampart module
on the org.apache.axis2.client.ServiceClient associated with your stub instance. This step is necessary even if you include your Rampart configuration information in the WSDL. Unfortunately, there does not appear to be any working way to engage
Rampart at the operation or message level in the current code, so part
of the benefit of granular WS-Security is lost at present when it's
used with an Axis2 client.
If you keep your Rampart configuration separate from the WSDL, as recommended, you also need to apply that configuration to the service description. Listing 2 shows the client code used for this purpose in the sample application. It calls the applyPolicy() method to add the policy containing the Rampart configuration to the service definition.
Listing 2. Configuring client-side operations
// create the client stub
String target = args[0] + "://" + args[1] + ":" + args[2] + args[3];
System.out.println("Connecting to " + target);
LibraryGranularStub stub = new LibraryGranularStub(target);
// configure and engage rampart module
ServiceClient client = stub._getServiceClient();
client.getAxisService().applyPolicy(loadPolicy("rampart-client-policy.xml"));
client.engageModule("rampart");
// set the username and password for requests which use them
Options options = client.getOptions();
options.setUserName("libuser");
options.setPassword("books");
|
The Listing 2 code sets the username and password on the ServiceClient options, meaning these are defined for all operations using that service even though they're only used by a single operation. Unlike engaging the Rampart module for all operations, setting the username and password in this way does no harm — the values are used only when needed by Rampart to construct a UsernameToken, and are otherwise ignored.
The policy document containing the Rampart configuration is shown in Listing 3. This is the same policy used in "Axis2 WS-Security signing and encryption," now extracted into a separate policy document.
Listing 3. Rampart client configuration policy
<wsp:Policy 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>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>clientkey</ramp:user>
<ramp:passwordCallbackClass
>com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>
<ramp:signatureCrypto>
<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type"
>JKS</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file"
>client.keystore</ramp:property>
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.password"
>nosecret</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy> |
The Ant build.xml included in the code download handles generating both client and server code from the WSDL, compiling the code, and generating the service AAR file. It also copies the Rampart configuration policy (supplied in the download as rampart-client-policy.xml, in the root directory) into the client classpath, along with performing some server-side policy handling discussed in the next section.
If you want to keep your server-side Rampart configuration out of the WSDL (generally a very good idea!) you need to include it in the services.xml file instead. In earlier articles, you saw this done for a complete WS-SecurityPolicy configuration, including the Rampart configuration, and applied to the service as a whole. This time around, the Rampart configuration policy is the only part added to the services.xml, and it's done at the operation level.
The policy document containing the Rampart configuration is shown in Listing 4. Like the client-side equivalent, this is the same policy used in "Axis2 WS-Security signing and encryption," now extracted into a separate policy document.
Listing 4. Rampart server configuration policy
<wsp:Policy 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>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>serverkey</ramp:user>
<ramp:passwordCallbackClass
>com.sosnoski.ws.library.adb.PWCBHandler</ramp:passwordCallbackClass>
<ramp:signatureCrypto>
<ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
<ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type"
>JKS</ramp:property>
<ramp:property name="org.apache.ws.security.crypto.merlin.file"
>server.keystore</ramp:property>
<ramp:property
name="org.apache.ws.security.crypto.merlin.keystore.password"
>nosecret</ramp:property>
</ramp:crypto>
</ramp:signatureCrypto>
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy> |
The Ant build.xml uses a PolicyTool program included in the code download to merge the Listing 4 policy (supplied in the download as rampart-server-policy.xml, in the root directory) into the services.xml. The modified services.xml is shown in Listing 5 (edited for width and length):
Listing 5. services.xml after additions
<serviceGroup>
<service name="library-granular">
<messageReceivers>
<messageReceiver class=
"com.sosnoski.ws.library.adb.LibraryGranularMessageReceiverInOut"
mep="http://www.w3.org/ns/wsdl/in-out"/>
</messageReceivers>
<parameter name="ServiceClass"
>com.sosnoski.ws.library.adb.LibraryGranularImpl</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>.../getBookResponse</outputActionMapping>
</operation>
<operation mep="http://www.w3.org/ns/wsdl/in-out" name="getBooksByType"
namespace="http://ws.sosnoski.com/library/wsdl">
<actionMapping>urn:getBooksByType</actionMapping>
<outputActionMapping>.../getBooksByTypeResponse</outputActionMapping>
<module ref="rampart"/>
<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">
<wsp:ExactlyOne>
<wsp:All>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>serverkey</ramp:user>
...
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</operation>
<operation mep="http://www.w3.org/ns/wsdl/in-out" name="addBook"
namespace="http://ws.sosnoski.com/library/wsdl">
<actionMapping>urn:addBook</actionMapping>
<outputActionMapping>
http://ws.sosnoski.com/library/wsdl/Library/addBookResponse
</outputActionMapping>
<module ref="rampart"/>
<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">
<wsp:ExactlyOne>
<wsp:All>
<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
<ramp:user>serverkey</ramp:user>
...
</ramp:RampartConfig>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
</operation>
</service>
</serviceGroup> |
In Listing 5, you can see that a Rampart module reference and a copy of the server configuration policy have been added to the definitions of the two operations using WS-Security, getBooksByType, and addBook. These changes configure the service to engage Rampart only for those two operations, and to use the supplied settings for Rampart's key and certificate access.
If you build and deploy the generated AAR file to an Axis2 server installation, you can see the effect of this in the Administration/Available Services page, where the modules engaged for each operation defined on the service are listed. If you run the client code and monitor the message exchange (using a tool such as TCPMon, described in "Axis2 WS-Security basics"), you'll see that the security handling works as desired, with:
- No WS-Security headers on the
getBookmessages - A WS-Security header with a
UsernameTokenon thegetBooksByTyperequest message - A WS-Security header with signatures on the
addBookrequest (but not the response) message
Axis2 and Rampart are currently (that is, with the current Axis2 1.5 release and a nightly build of Rampart) able to handle basic WS-SecurityPolicy configurations embedded in WSDL, including granular policies defined at the operation or message level. However, some of the configurations tested for this article would not work with Axis2/Rampart. For instance, trying to set the UsernameToken policy for the addBook operation (in addition to the signing policy on the input message) resulted in an error apparently related to encryption in the Rampart code (even though no encryption was being used). Judging from this experience, and from some of the problem reports, it looks like the Axis2/Rampart WS-SecurityPolicy handling is good for simple configurations reflecting common use cases but prone to failure when applied to unusual combinations.
Another issue is that the overhead of engaging Rampart on the server will always occur on both request and response handling even if you're using WS-Security for only one of the messages (as discussed in "The high cost of (WS-)Security"). On the client side, the situation is even worse — because engaging Rampart on the client is currently an all-or-nothing proposition, if you use WS-Security on any operation you'll have to live with the Rampart overhead on every operation.
Finally, the current Axis2/Rampart WS-Policy handling does not support policy alternatives. Alternatives are a major feature of the WS-Policy design, allowing services to let clients choose which of two or more acceptable configurations are to be used when they access the service. The Axis2/Rampart policy implementation does not support this feature, instead ignoring everything except the first alternative.
With this article and the previous three, the Java Web services series has covered all the major aspects of WS-Security and WS-SecurityPolicy handling in Axis2/Rampart, including performance issues. In future installments, you'll see how other Java Web services frameworks work with WS-Security and WS-SecurityPolicy, but first there are a couple other aspects of Axis2 to look into.
One issue that is important to many organizations is the support for Java Architecture for XML Binding (JAXB) 2.X. JAXB 2.X is the official Java standard for XML data binding, and although open source alternatives offer their own benefits, some organizations want to stick to the standard. In the next article, you'll see how you can use JAXB 2.X data binding with Axis2, and learn how it compares to the other data-binding choices supported by Axis2.
| Description | Name | Size | Download method |
|---|---|---|---|
| Source code for this article | j-jws7.zip | 29KB | HTTP |
Information about download methods
Learn
-
Apache Axis2/Java: Find information on Axis2 development and status, along with links for mailing lists, issue tracking, and downloads.
-
Rampart: Learn more about the Rampart WS-Security module for Axis2.
-
"Web services and Axis2 architecture" (Eran Chinthaka, developerWorks, November 2006): Learn how modules such as Rampart extend Axis2.
-
Understanding Web Services specifications: This series of tutorials introduces many of the important Web services standards, including:
- "Understanding Web Services specifications: Web Services Description Language (WSDL)" (Nicholas Chase, developerWorks, July 2006)
- "Understanding Web Services specifications: WS-Security" (Nicholas Chase, developerWorks, August 2006)
- "Understanding Web Services specifications: WS-Policy" (Tyler Anderson, developerWorks, February 2007).
-
OASIS Web Services Security (WSS) TC: This is the organization responsible for the WS-Security specification and token profiles. You can find links hereto all versions of these standards.
-
The W3C Web Services Policy Working Group: This group defines the WS-Policy specification.
-
OASIS Web Services Secure Exchange (WS-SX) TC: This organization is responsible for WS-SecurityPolicy, WS-SecureConversation, and WS-Trust specifications.
-
Browse the
technology bookstore for books on these and other technical topics.
-
developerWorks Java technology zone: Find hundreds of articles about every aspect of Java programming.
Get products and technologies
-
Apache Axis2: Download the latest Axis2 release.
-
Rampart: Download the Rampart module for Axis2.
- Download IBM product evaluation versions or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Get involved in the My developerWorks community.

Dennis 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.
Comments (Undergoing maintenance)





