Unity Logo

WS-Security

WS-Security support is now included in the 1.1 release. XFire uses WSS4J to provide WS-Security support. In addition to the documentation here, you may find their site helpful as well. XFire also includes some WS-Security examples in the distribution which you can try out.

Enabling WS-Security

Before enabling WS-Security module, you must make sure that you have installed Unlimited Strength Jurisdiction Policy Files for your SDK version ( bottom of the page http://java.sun.com/j2se/1.5.0/download.jsp or http://java.sun.com/j2se/1.4.2/download.html), and the Bouncy Castle security provider from http://BouncyCastle.org ( Here is short description of instalation process : http://docs.safehaus.org/display/PENROSE/Installing+Security+Provider ) . If you don't, you will probably receive an exception message about invalid algorithm or key size.

To enable WS-Security support you must add two handlers to the incoming (inhandlers) and/or outgoing (outhandlers) handler chains ( If your client sends secured data but does not expect to get such response, its enough to only add security handlers to the client's outHandlers and if your server takes secured messages but does not send such, you can add handlers only to the server's inHandlers chain). These handlers must be added to the inHandlers:

org.codehaus.xfire.security.wss4j.WSS4JInHandler - Performs the WS-Security related functions

org.codehaus.xfire.util.dom.DOMInHandler - Converts from StAX to DOM format for WS-Security

Note: DOMInHandler requires XML Transformer support which is included in Xalan 2.7.0.  This library is not included with XFire by default.

and the handlers below to outHandlers:

org.codehaus.xfire.security.wss4j.WSS4JOutHandler - Performs the WS-Security related functions

org.codehaus.xfire.util.dom.DOMOutHandler - Converts from DOM to StAX format for WS-Security

Server side configuration :

<tns:inHandlers>
 <tns:handler handlerClass="org.codehaus.xfire.util.dom.DOMInHandler" />
 <bean id="org.codehaus.xfire.security.wss4j.WSS4JInHandler" class="org.codehaus.xfire.security.wss4j.WSS4JInHandler">
   <!-- security configuration goes here  -->
   ....
 </bean>
</tns:inHandlers>

<tns:outHandlers>
 <tns:handler handlerClass="org.codehaus.xfire.util.dom.DOMOutHandler" />
 <bean id="org.codehaus.xfire.security.wss4j.WSS4JOutHandler" class="org.codehaus.xfire.security.wss4j.WSS4JOutHandler">
   <!--  security configuration goes here -->
   ....
</bean>
</tns:outHandlers>





Client side configuration :



Service serviceModel = new ObjectServiceFactory().create( .. )
// Create service client
IBook service = (IBook) new XFireProxyFactory().create( ...);
Client client = Client.getInstance(service);
client.addOutHandler(new DOMOutHandler());
Properties outProperties = new Properties();
// CONFIGURE OUTGOING SECURITY HERE (outProperties) <--
client.addOutHandler(new WSS4JOutHandler(outProperties));
client.addInHandler(new DOMInHandler());
Properties inProperties = new Properties();
// CONFIGURE INCOMMING SECURITY HERE (inProperties) <--
client.addInHandler(new WSS4JInHandler(inProperties));
// Execute service







Building keys

You can generate a key pair for the development environment via the following steps.  Keep in mind these will not be signed by an external authority like Verisign.

1. Creating private key with given alias and password like "myAlias"/"myAliasPassword" in keystore (protected by password for

security reasons)





In this instance we are using the RSA algorithm.

2. Self-sign our certificate (in production environment this will be done by a company like Verisign).





3. Export the public key from our private keystore to file named key.rsa







4. Import the public key to new keystore:







So now we have two keystores containing our keys - a public one (publicstore.jks) and a private one (privatestore.jks). Both of them have keystore password set to keyStorePass (this not recommended for production but ok for development) and alias set to myAlias. The file key.rsa can removed from filesystem, since it used only temporarily.  Storing keys in keystores is strongly advised because a keystore is protected by a password.

A more detailed description of key generation can be found here:

http://www.churchillobjects.com/c/11201e.html

http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/keytool.html

How to create a production certificate can be found here:

http://support.globalsign.net/en/objectsign/java.cfm

User Token Authentication

This WS-Security scenario adds username and password values to the message header. A password can be sent as plain text or in hashed form (depending on "passwordType" property). 

Client side configuration :





The PasswordHandler class is responsible for finding the password for given user name and must implement the org.apache.ws.security.WSPasswordCallback interface.

You can also specify an existing handler instance, using the WSHandlerConstants.PW_CALLBACK_REF property on the client/service instance or MessageContext ( e.g. client.setProperty(new PasswordHandler())).

The WSHandlerConstants.PASSWORD_TYPE property determines how the password will be sent.  If it is set to WSConstants.PW_TEXT, the password will be sent as plain text.  If the value is WSConstants.PW_DIGEST, a password digest will be sent. If no value is set, a digest is used by default..

Server side configuration :





The "action" property contains an action to perform.

The "passwordCallbackClass" property contains the handler class name which will process the password sent with the SOAP message. If the password is in plain form, the callback class can authenticate the user or just ignore the password and let the XFire handler perform the authentication with a data set on the MessageContext by security handler. In the case of a hashed password, the callback class MUST return the same password as used on client side.  If a null value is returned or the password doesn't match the orignal password, an exception will be thrown. Security processing ( like username/password from usertoken header ) can be retrieved from MessageContext with the following code :









Timestamps

Timestamps specify how long the security data remains valid.

Client side configuration:

 





The WSHandlerConstants.TTL_TIMESTAMP  property specifies the number of seconds or milliseconds for which the message is considered valid .

The WSHandlerConstants.TIMESTAMP_PRECISION property determines the time unit for the time stamp ( seconds or miliseconds).  If not specified, seconds are used.

Server side configuration: 







Encryption

Allows one to encrypt the message body ( or only  its part ) using the given crypthography algorithm.  For performance reasons, message data is encrypted using a symmetric key and then the symmetic key is encrypted with the receiver's public key.

Client side configuration:





WSHandlerConstants.ENC_PROP_FILE - contains path to file with details of encryption configuration.

WSHandlerConstants.ENC_SYM_ALGO - specify symmetric algorithm used to encrypt message data. Allowed values are :    WSConstants.TRIPLE_DES,WSConstants.AES_128 ( default ), WSConstants.AES_256, and WSConstants.AES_192

The file can look like the following :

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=aliaspass
org.apache.ws.security.crypto.merlin.keystore.alias=alias
org.apache.ws.security.crypto.merlin.file=META-INF/xfire/myPublicstore.jks





 

org.apache.ws.security.crypto.provider -  implementation class for security provider ( must be  set to org.apache.ws.security.components.crypto.Merlin )

org.apache.ws.security.crypto.merlin.keystore.type - keystore type ( jks/pkcs12 )

org.apache.ws.security.crypto.merlin.keystore.password - keystore passphrase

org.apache.ws.security.crypto.merlin.keystore.alias - alias of key inside keystore

org.apache.ws.security.crypto.merlin.alias.password -  password for private key inside keystore stored under given alias ( not used for encryption )

org.apache.ws.security.crypto.merlin.file - path to keystore

Server side configuration:







Signature

Allows one to send along with the message a digital signature of it, which assures that no one modified the message content between the sender and receiver.  This action creates a digest of the message and encrypts it with sender private key.  The receiver must have the sender's public key to verify this signature.

Client side configuration:





WSHandlerConstants.SIG_KEY_ID specify what key identifier should be used ( possible values are : "IssuerSerial" ( recommended ) and "DirectReference" ).

WSHandlerConstants.SIG_PROP_FILE contains path to file with details of signature configuration.

Configuration file can look like:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.alias.password=aliaspass
org.apache.ws.security.crypto.merlin.keystore.alias=alias
org.apache.ws.security.crypto.merlin.file=META-INF/xfire/myPrivatestore.jks





 

Inserting a certicate in the signing message : http://ws.apache.org/wss4j/cert.html

Server side configuration:





The file insecurity_sign.properties:



org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=keystorePass
org.apache.ws.security.crypto.merlin.keystore.alias=alias
org.apache.ws.security.crypto.merlin.file=META-INF/xfire/myPublicstore.jks







Using WS-Security with JSR 181 Annotations

This blog entry shows how to configure WS-Security using JSR 181 Annotations and InHandlers.

Using encrypted passwords in configuration files

 XFire allows you to use encrypted passwords in WS-Security configuration files.

To use this feature you must add following two lines:

Custom Encrypter is a simple class (which extend AbstractDecrypter ) implementing any  algorithm used to decrypt passwords. 



© 2003-2008 Codehaus