This page discusses various topics regarding usage of WSS4J. See the Using Apache WSS4J page for web stack-specific usage notes.
WSS4J uses the Crypto interface to provide a pluggable way of retrieving and converting certificates, verifying trust on certificates etc. Two implementations are provided out of the box by WSS4J -- the standard Merlin implementation which holds one keystore and one truststore and Certificate Store that holds an array of X509Certificates, however presently is only useful for signature verification and encryption (cannot be used for decryption or signing).
In WSS4J 1.5.x, trust validation of public keys involved construction of a PublicKeyCallback instance, passing it the PublicKey object, and invoking the CallbackHandler. It then called a "isVerified" method on the Callback to check to see whether the CallbackHandler had verified the PublicKey or not. The CallbackHandler implementation needed to call the "verifyTrust" method on the PublicKeyCallback, passing in a KeyStore object. This method iterates through each Certificate in the KeyStore, and checks to see whether the PublicKeys match.
In WSS4J 1.6.x, trust validation of public keys was moved from a WSS4J 1.5's PublicKeyCallback instance to the Crypto interface, where the argument is now a PublicKey object. In this way, validation is done using the same interface as for trust validation for Certificates, and the end-user has no need to consider the special-case of verifying public keys in the CallbackHandler, as it is taken care of internally by WSS4J.
WSS4J 1.6 introduces the concept of a Validator, for validating credentials that have been processed by a Processor instance.
An inbound security header is processed by WSS4J by iterating through each child element of the header, and by calling the appropriate Processor implementation to deal with each element. In WSS4J 1.5.x, some processors perform validation on the received token (e.g. UsernameTokens), whereas others store the processing results for later verification by third-party WS-Handler implementations (e.g. Timestamp verification, Certificate trust verification). There are some problems with this approach:
WSS4J 1.6 has moved Timestamp verification and certificate trust validation back into the processing of the security header, thus solving the first three points above. The fourth point is met by the new concept of Validators, as well as some changes to the way Processors and CallbackHandler implementations are used in WSS4J 1.6.
In WSS4J 1.5.x, CallbackHandler implementations are used in different ways by different processors, sometimes they are expected to verify a password (as for processing UsernameTokens), and other times they are expected to supply a password (as for decryption). In WSS4J 1.6, CallbackHandler implementations are only expected to supply a password (if it exists) to the processors. The Processor implementations do not perform any validation of the security token, instead they package up the processed token, along with any (password) information extracted from the CallbackHandler, and hand it off to a Validator implementation for Validation.
The Processor implementations get the specific Validator implementation to use via the RequestData parameter, which in turn asks a WSSConfig object for the Validator implementation. If the Validator is null, then no Validation is performed on the received token. The Processor then stores the received token as normal. WSS4J 1.6 comes with several default Validators, which are:
There are some additional WSSecurityEngineResult constants that pertain to the Validator implementations:
To validate an inbound UsernameToken in some custom way, simply associate the NoOpValidator with the UsernameToken QName in the WSSConfig of the RequestData object used to supply context information to the processors. After WSS4J has finished processing the security header, then extract the WSSecurityEngineResult instance corresponding to the WSConstants.UT action, and perform some custom validation on the token.
To validate plaintext passwords against a directory store, rather than have the CallbackHandler set the password: Simply @Override the verifyPlaintextPassword(UsernameToken usernameToken) method in the validator. By simply plugging in a validator on the UsernameTokenProcessor (such as the NoOpValidator), it is possible to do any kind of custom validation (or none at all) on the token.
An example of how to add a custom Validator implementation is the STSTokenValidator in CXF 2.4.0. The STSTokenValidator tries to validate a received SAML Assertion locally, and if that fails, it dispatches it to a Security Token Service (STS) via the WS-Trust interface for validation. It also supports validating a UsernameToken and BinarySecurityToken in the same manner. The SecurityConstants class defines some configuration tags for specifying a custom validator for inbound SAML1, SAML2, UsernameToken, BinarySecurityToken, Signature and Timestamps. The STSTokenValidator can be configured by associating it with the appropriate configuration tag.
The signature and encryption creation code in WSS4J uses the WSEncryptionPart class to find DOM elements to sign and encrypt. There are a number of minor changes to how elements are located from a WSEncryptionPart in WSS4J 1.6:
WSEncryptionPart is intended to refer to a single Element for encryption/signature. However, as a localname/namespace is not necessarily unique, point 4 will return all matching Elements. An important implication of the order of the steps given above, is that client code should set the DOM element on the WSEncryptionPart if it is accessible, and if not, it should set the wsu:Id. Otherwise, a localname/namespace (which is not referring to the SOAP Body) will result in a traversal of the DOM tree.
The DOM element(s) that is(are) found are stored for retrieval, so that we don't need to traverse the SOAP envelope multiple times, when e.g. doing an STR Transform, or for element location in the XML Security code.
The WSPasswordCallback class defines a set of integers which correspond to usage instructions for the CallbackHandler. In WSS4J 1.6, the following WSPasswordCallback identifiers are used:
The CallbackHandler interface receives and requires the following information when handling UsernameTokens:
Support for SAML2 assertions has finally arrived in WSS4J, via the forthcoming 1.6 release. This has been a long-standing feature request. WSS4J 1.5.x only supports SAML 1.1 assertions via the deprecated Opensaml1, and it supports them in a very limited manner, namely:
Several patches were submitted to WSS-146 to upgrade WSS4J to use Opensaml2. SAML2 support in WSS4J 1.6 consists of:
WSS4J 1.6 contains an extensive set of tests for both creating and processing different type of assertions. To illustrate the flexibility and simplicity of the CallbackHandler approach for constructing assertions, take a look at an abstract CallbackHandler here, as well as the concrete implementations (SAML 1.1 and SAML 2). As you can see, a fairly small amount of code can create a large variety of assertions.
Opensaml2 has a very large set of dependencies, but through some judicious pom exclusions, as well replacing the Opensaml DefaultBootstrap code to avoid loading velocity, the following dependencies are introduced in WSS4J via Opensaml (snippet from mvn dependency):
+- org.opensaml:opensaml:jar:2.4.1:compile | \- org.opensaml:openws:jar:1.4.1:compile | \- org.opensaml:xmltooling:jar:1.3.1:compile | +- org.slf4j:slf4j-api:jar:1.6.1:compile | \- joda-time:joda-time:jar:1.6.2:compile
The WSS4J 1.6 pom currently has a dependency on the Shibboleth repo, where the Opensaml2 artifacts live. It is planned on getting the Opensaml2 artifacts into Maven central in time for the 1.6 release - this is slightly complicated by the fact that some of the Opensaml2 dependencies are themselves not in Maven Central.
One known issue is that WSS4J cannot create an Assertion which has an EncryptedKey element in the Subject. This is due to a bug in Opensaml2 which has been fixed, but not released yet.
The Opensaml2 port has a large impact on existing code for *creating* assertions, however it is thought that very few people used that code. It has a minimal impact on existing code for processing assertions, with several caveats:
WSS4J 1.6 has been ported to use the JSR 105 API for XML Digital Signature. Previously, WSS4J 1.5.x used the custom API of the Apache Santuario XML Security for Java library to create and process XML Digital Signatures.
WSS4J 1.6 has a minimum requirement of JDK 1.5 (note that WSS4J 1.5.x supports JDK 1.4). As JDK 1.5 does not contain an implementation of JSR 105, this means that XML Digital Signature is done via the JSR 105 implementation of Apache Santuario. However, when JDK 1.6+ is used, WSS4J 1.6 uses the JDK implementation of JSR 105 for signature creation and verification. You can override this by endorsing the Santuario jar.
The Apache Santuario XML Security jar is still required for the JDK 1.6 case, as there are compile-time dependencies in WSS4J for encryption/decryption, as well as for some algorithm parsing, and resource resolver stuff. One downside to the Santuario jar, is its dependence on Xalan for a small subset of operations. This dependency will be removed for the 1.5 release of that library (in a few months).
It is worth noting some changes to the main class used in WSS4J for signature creation as a result of the JSR-105 port. In WSS4J 1.5.x, after the signature certs and list of references to sign had been configured, the "computeSignature" method was called to compute the signature. The DOM element corresponding to the signature was independent of the pre-existing security header, and could be extracted later and inserted into the security header.
In WSS4J 1.6, you must tell "computeSignature" where to insert the signature element. A boolean "prepend" argument allows you to configure whether to prepend the generated Signature element to the security header, or whether to append it. If prepend is true, then an optional siblingElement argument can be used to prepend the signature element before this sibling element. Once computeSignature has been called, you have no control over where the signature element is inserted into the security header.
The Basic Security Profile (BSP) 1.1 specification provides an industry-standard way of making sure that different WS-Security stacks can communicate with each other, by clarifying and narrowing the scope of the various WS-Security standards. WSS4J 1.5.x does not implement the BSP in any meaningful way. The WSSConfig class supports a "isWsiBSPCompliant" method (default is false), which will enable the generation of an InclusivePrefix list for signature generation, something that is mandated by the BSP spec.
WSS4J 1.6 provides support for the BSP 1.1 specification, in so far as it pertains to the core WS-Security specifications that WSS4J supports. The enforcing of BSP compliance for inbound messages is controlled by the WSSConfig class, as per WSS4J 1.5.x. An important change is that BSP compliance is now turned on by default. In addition, a new WSHandlerConstants configuration parameter has been added so that BSP compliance can be controlled via a WSHandler implementation.