Java Web services Axis2 WS-Security basics

Document Sample
Java Web services  Axis2 WS-Security basics Powered By Docstoc
					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 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="" ...>
  <wsse:Security soap:mustUnderstand="1">
   <wsu:Timestamp wsu:Id="Timestamp-d2e3c4aa-da82-4138-973d-
   <wsse:BinarySecurityToken ValueType="...-x509-token-profile-
   <xenc:EncryptedKey xmlns:xenc="">
Algorithm="" />
    <KeyInfo xmlns="">
      <wsse:KeyIdentifier ValueType=

     <xenc:DataReference URI="#EncryptedContent-ba0556c3-d443-4f34-bcd1-
14cbc32cd689" />
   <Signature xmlns="">
       xmlns:ds="" />
     <SignatureMethod Algorithm="
sha1" />
     <Reference URI="#Id-c80f735c-62e9-4001-8094-702a4605e429">
       <Transform Algorithm="" />
      <DigestMethod Algorithm="" />
      <wsse:Reference URI="#SecurityToken-faa295..."
         ValueType="...-x509-token-profile-1.0#X509v3" />
 <soap:Body wsu:Id="Id-8db9ff44-7bef-4737-8091-cdac51a34db8">
  <xenc:EncryptedData Id="EncryptedContent-ba05..."

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
Back to top
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 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:

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.
Back to top
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
The root directory of the example code is jws04code. Inside this
directory, you'll find Ant build.xml and files, the
library.wsdl file giving the service definition for the example
application, a 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 file
configures the operation of the example application. Listing 2 shows the
supplied version of this properties file:
Listing 2. Supplied file# set axis-home to your Axis2
installation directory
# set the connection protocol to be used to access services (http or
# set the name of the service host
# set the port for accessing the services (change this for monitoring)
# set the base path for accessing all services on the host
# set the name of the policy file to be used by the client
# set the name of the policy file to be used by the server
Before trying out the examples, you need to edit the
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.
Back to top
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=
          <sp:UsernameToken sp:IncludeToken="

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">


    <parameter name="useOriginalwsdl">true</parameter>
    <parameter name="modifyUserWSDLPortAddress">true</parameter>
    <operation mep="" name="getBook"


    <module ref="rampart"/>
    <wsp:Policy xmlns:wsp=""




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
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
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
Listing 5. Password callback codeimport;

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() ==

                 // 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 " +
                " protocol
host port path");

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

           // configure and engage Rampart
           ServiceClient client = stub._getServiceClient();
           Options options = client.getOptions();

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
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 applicationJust 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 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'
    <wsse:Security xmlns:wsse="...wss-wssecurity-secext-1.0.xsd"
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
        <wsse:Password Type="...wss-username-token-profile-
    <ns2:getBooksByType xmlns:ns2="">

Back to top
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
Listing 8. Policy requiring HTTPS connection
<wsp:Policy wsu:Id="UsernameToken" xmlns:wsu=
          <sp:HttpsToken RequireClientCertificate="false"/>
     <sp:UsernameToken sp:IncludeToken="

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
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 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=
          <sp:UsernameToken sp:IncludeToken="

<?xml version='1.0' encoding='UTF-8'?>
    <wsse:Security xmlns:wsse=".../oasis-200401-wss-wssecurity-secext-
      <wsse:UsernameToken xmlns:wsu="...wss-wssecurity-utility-1.0.xsd"
         <wsse:Password Type="...wss-username-token-profile-
    <ns2:getBooksByType xmlns:ns2="">

Back to top
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.
Back to top
DescriptionNameSizeDownload methodSource code for this article
Information about download methods

Shared By: