The FAQ for WSS4J

In the FAQ we try to gather a set of frequently asked questions and the answers to them.

This FAQ is a living page, please feel free to add new items to it if you feel that this information is worth to share with your fellow WSS4J users.

  1. What is WSS4J?

  2. What is WSS4J not?

  3. Encryption, decryption, signature, certificates, ...

  4. Where can i get info on the parameters for WSS4J handlers?

  5. Problems and errors with Signature verification

  6. No such algorithm: http://www.w3.org/2001/04/xmlenc#rsa-1_5 or similar

  7. Spurious Null Pointer Exception

  8. Where can I change the debug level of wss4j?

  9. I have many clients and one service (and I need signature+encryption). Is there a way to handle many client certs?

  10. How can a Web Service check and access the results of security actions?

  11. Timestamp handling in WSS4J

What is WSS4J?

WSS4J is part of the Apache Web Services project. Here is link to all Apache Web Service projects.

Apache WSS4J is an implementation of the OASIS Web Services Security specifications (WS-Security, WSS) from OASIS Web Services Security TC. WSS4J is primarily a Java library that can be used to sign, verify, encrypt, and decrypt SOAP Messages according to the WS-Security specifications. This library is independent of underlying SOAP engines. The link between WSS4J and SOAP engines is provided by handlers.

On top of this library we also implemented handlers for the Axis SOAP engine and for OAP engines that use JAX-RPC specifications.

Here is the link to the OASIS WS-Security specifications.

What is WSS4J not?

WSS4J is not a tool to

Encryption, decryption, signature, certificates, ...

This is what WSS4J is all about. To use WSS4J you shall have at least a basic understanding of all this. For a very first start have a look into this text. At the reference section you'll find more pointers to the relevant standards and other information.

Where can i get info on the parameters for WSS4J handlers

Sample Parameters for WSS4J handlers

Problems and errors with Signature verification

In this case you often an error or waring message similar to this one:

08:24:58,371 WARN  [Reference] Verification failed for URI "#id-22221245"
org.apache.ws.security.WSSecurityException: The signature verification failed
       at org.apache.ws.security.WSSecurityEngine.verifyXMLSignature(WSSecurity
Engine.java:644) 
...

Most often this problem occurs if the request message was modified after it was signed. Mostly this is due to some pretty printing where the request message was modified to look nicer. This pretty printing inserts newlines, blanks and tabs. Very often people think that these additional charaters are removed by canonicalization (c14n) of the message. This is a common misunderstanding.

C14n does not remove these newlines or other significant whitespace. For more information on c14n refer to Canonical XML.

Another very common cause of this error is forgetting to turn off namespace optimisation in your WSDD file. You need a line like this:

 <globalConfiguration>
   <parameter name="enableNamespacePrefixOptimization" value="false" />
 </globalConfiguration>

Leaving namespace optimisation on will cause axis to modify the signed message, invalidating the signature, if the message is not exactly in axis's preferred format. This prevents interoperability with other systems, such as .NET's WSE implementation.

No such algorithm: http://www.w3.org/2001/04/xmlenc#rsa-1_5 or similar

In most case this is a problem of a security provider. Depending on the used Java SDK several problems may show up:

Other Java SDKs also may have problems to initialize and install the correct security provider.

Spurious Null Pointer Exception

Sometimes we get reports about a Null Pointer Exception (NPE) during WSS4J processing. In many cases this is due to a non namespace aware XML parser. Sun's Java 1.4.x uses the Crimson XML parser as default parser. This parser has problems supporting namespaces.

If you have a NPE please check the stacktrace if you find a class similar to org.apache.crimson.tree.ElementNode2. In this case you use the Crimson parser. Please make sure that a full namespace aware parser is in the classpath, e.g. Apache Xerces. Of course this is also true for other parsers that do not support XML namespace.

There is also a NullPointerException you can get that doesn't contain "crimson" anywhere. The top of the stack-trace looks like this:

WSHandler: Signature: error during message procesing... 
Signature creation failed; nested exception is: 
  java.lang.NullPointerException; nested exception is: 
  org.apache.ws.security.WSSecurityException: ...: Signature creation failed; nested exception is: 
  java.lang.NullPointerException
  at org.apache.ws.axis.security.WSDoAllSender.invoke(WSDoAllSender.java:201)
  at org.apache.axis.strategies.InvocationStrategy.visit(InvocationStrategy.java:32)
 ...nested exception is: 
  java.lang.NullPointerException
  at org.apache.ws.security.handler.WSHandler.performSIGNAction(WSHandler.java:203)
 ...

To determine what JAXP implementation is being loaded use the following code:

   System.out.println(javax.xml.parsers.DocumentBuilderFactory.newInstance());

and if the class name isn't org.apache.xerces.jaxp.DocumentBuilderFactoryImpl then the Xerces jar isn't in your classpath (or it's being masked by the javax.xml.parsers.DocumentBuilderFactory System property or another JAXP-enabled XML parser on the classpath or the JRE/lib/jaxp.properties file).

Where can I change the debug level of wss4j?

The WSS4J functions and handlers use log4j to output debug and other messages during runtime. To control the output level, the output target, and the output format use the standard log4j property file. The src directory contains a predefined log4j.properties file that you can take as an example.

In this property file just enable the modules you would like to trace and put the file into the classpath. For more detailed information about log4j please refer to the Apache logging project.

I have many clients and one service (and I need signature+encryption). Is there a way to handle many client certs?

Each client has its own certificate, the requests shall be signed and encrypted. The responses also signed and encrypted.

Well, to keep the effort of the certificate adminsitration low I usually use the following technique. Using this way no special programming on the client or service is required, all handled via standard deployment.

Client part, request:

Server part, request:

Server part, response:

Client part, response:

As pointed out, usually no modification in client/service coding is necessary, also no need to change the trust handling inside WSDoAllReceiver except that you need a very special certificate trust verification.

How can a Web Service check and access the results of security actions?

MessageContext msgContext = MessageContext.getCurrentContext();
Vector results = (Vector) msgContext.getProperty(WSHandlerConstants.RECV_RESULTS);
log.trace("Potential number of usernames: " + results.size());
for (int i = 0; results != null && i < results.size(); i++) {
    WSHandlerResult hResult = (WSHandlerResult) results.get(i);
    Vector hResults = hResult.getResults();
    for (int j = 0; j < hResults.size(); j++) {
        WSSecurityEngineResult eResult = (WSSecurityEngineResult) hResults.get(j);
        // An encryption or timestamp action does not have an associated principal,
        // only Signature and UsernameToken actions return a principal
        if ((eResult.getAction() == WSConstants.SIGN)
            || (eResult.getAction() == WSConstants.UT)) {
            // Signature and UsernameToken actions return a principal
            System.out.println("Principal's name: " + eResult.getPrincipal().getName());
        } else if (eResult.getAction() == WSConstants.ENCR) {
            // Encryption action returns what ?
        } else if (eResult.getAction() == WSConstants.TS) {
            // Timestamp action returns a Timestamp
            System.out.println("Timestamp created: " + eResult.getTimestamp().getCreated());
            System.out.println("Timestamp expires: " + eResult.getTimestamp().getExpires());
        }
    }
}

The getter methods of WSSecurityEngineResult are depreciated. The new version of WSSecurityEngineResult inherits from Java's HashMap. Web Services shall use the standard get() to retrieve data from WSSecurityEngineResult (see examples below).

The WSS4J handler stores the results in the Axis message context.

At first the web service fetches the vector that contains the results of all WSS4J handler invocations for a request. There maybe several invocation (chained handlers) because a request may contain several security elements for different actors.

The web service may check the actor's name in each WSHandlerResult using getActor() (not show above). If the actor's name matches or if this is the only handler result object the web service can check the result of each security action.

The web service gets the vector of the security results from the handler result using getResults(). This vector contains a number of WSSecurityEngineResult objects that contain further information for each performed secutity action.

Examples:

To get a principal:

java.security.Principal principal = (java.security.Principal)eResult.get(WSSecurityEngineResults.TAG_PRINCIPAL);

At this point the Web Service may check the principal's type, depending on the security action (see above). To get the action

int action = ((java.lang.Integer)eResult.get(WSSecurityEngineResults.TAG_ACTION)).intValue()

Accessible data in WSSecurityEngineResult depending on security actions

For Signatures the WSSecurityEngineResult map contains:

The web service can access these data using getter methods (deprectiated) or standard HashMap get methods. See the Javadoc documentation of WSSecurityEngineResults.

Timestamp handling in WSS4J

WSS4J supports several time features and options. If you just use the action Timestamp without any further configuration WSS4J uses the following defaults:

Use the following handler parameters to change these settings:

WSS4J uses the UTC timezone (zulu time) to generate timestamps. This is according to the WSS specifications.

At the receiving end WSS4J checks if the request is still valid (is not expired). This is done in two steps:

FrontPage/WsFx/wss4jFAQ (last edited 2009-09-20 22:47:58 by localhost)