Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Implementing WS-Security with Java and WSS4J : Page 4

Many organizations have now implemented solutions based on the promise of Web services, exposing those services over the Internet to enjoy maximum exposure—which then leaves them with the dilemma of securing their services to protect data and other resources. Find out how to use Java and Apache's Web Services Security for Java (WSS4J) framework to secure your Web services.


advertisement
Using the WSS4J Framework
Apache's WSS4J is a Java implementation of the OASIS Web Services Security (WS-Security) specification. WSS4J is a framework that you can use to sign and verify SOAP messages with WS-Security information. WSS4J uses the Apache Axis and Apache XML-Security projects and is interoperable with JAX-RPC server/clients and .NET server/clients. WSS4J implements Username Token profile V1.0 and X.509 Token Profile V1.0. WSS4J can generate and process the following SOAP Bindings:

  • XML Security
    • XML Signature
    • XML Encryption
  • Tokens
    • Username Tokens
    • Timestamps
    • SAML Tokens
WSS4J can secure Web services deployed in most Java Web services environments; however, it ships with specific support for the Axis Web services framework. You can use WSS4J in a standalone manner or in tandem with Axis to create and process WS-Security elements within a SOAP envelope. You can obtain the latest release of the WSS4J project by checking out the CVS module, ws-wss4j, using the following CVS path with any CVS client.

:pserver:anoncvs@cvs.apache.org:/home/cvspublic.

The tools in the next sections demonstrate how to use WSS4J to generate XML that conforms to the latest WS-Security specification.

Initializing the WSS4J Framework
First, you must initialize the WSS4J framework—in this case, to the default values. For example:

private static final WSSecurityEngine secEngine = new WSSecurityEngine();

Next, create a crypto provider. The default factory getInstance()method creates a provider according to the class name specified by the system property org.apache.ws.security.crypto.provider. If the provider property is not set, the getInstance() method creates a default class instance, org.apache.ws.security.components.crypto.BouncyCastle.

The provider is initialized to the values specified in the crypto.properties file found in the WSS4J .jar file. As shipped, that file specifies org.apache.ws.security.components.crypto.Merlin as the provider class.



private static final Crypto crypto = CryptoFactory.getInstance();

You use the AxisClient as the context engine for messaging operations.

private AxisClient engine = null; private MessageContext msgContext = null; public WSSecuritySample() { engine = new AxisClient(new NullProvider()); msgContext = new MessageContext(engine); }

Creating the Target SOAP Envelope
The following method creates and returns an Axis message from a SOAP envelope string.

private Message getAxisMessage(String unsignedEnvelope) { InputStream inStream = new ByteArrayInputStream( unsignedEnvelope.getBytes()); Message axisMessage = new Message(inStream); axisMessage.setMessageContext(msgContext); return axisMessage; }

The SOAP envelope used in this article and passed to the getAxisMessage method shown above is illustrated as follows:

<SOAP-ENV:Envelope xmlns:SOAP-ENV=http://www.w3.org/2003/05/soap-envelope xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <sayHello xmlns= "http://jeffhanson.com/services/helloworld"> <value xmlns=""> Hello world! </value> </sayHello> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

Signing a SOAP Message
The following method uses the WSSignEnvelope class to sign a SOAP envelope and adds the signature data to the envelope in compliance with WS-Security.

public Message signSOAPEnvelope(SOAPEnvelope unsignedEnvelope) throws Exception { WSSignEnvelope signer = new WSSignEnvelope(); String alias = "16c73ab6-b892-458f-abf5-2f875f74882e"; String password = "security"; signer.setUserInfo(alias, password); Document doc = unsignedEnvelope.getAsDocument();

The "build" method creates the signed SOAP envelope. It takes a SOAP Envelope as a W3C Document and adds a WSS Signature header to it. The signed elements depend on the signature parts specified by the WSBaseMessage.setParts(java.util.Vector parts) method. By default, it signs the SOAP Body element.

The "crypto" parameter is the object that implements access to the keystore and handling of certificates.

WSS4J includes a default implementation, org.apache.ws.security.components.crypto.Merlin.

Document signedDoc = signer.build(doc, crypto); // Convert the signed document into a SOAP message. Message signedSOAPMsg = (org.apache.axis.Message)AxisUtil.toSOAPMessage(signedDoc); return signedSOAPMsg; }

Listing 1 shows a signed SOAP envelope as returned from the preceding method.

Adding Username Tokens to a SOAP Message
Listing 2 shows a WSS4J method that uses the WSEncryptBody class to add username tokens to a SOAP envelope in compliance with WS-Security.

The SOAP envelope contained within the Axis message returned from the method shown in Listing 2 will look similar to Listing 3:

Encrypting SOAP Messages
The following method uses the WSEncryptBody class to encrypt part of a SOAP envelope in compliance with WS-Security.

public Message encryptSOAPEnvelope( SOAPEnvelope unsignedEnvelope, Message axisMessage) throws Exception { WSEncryptBody encrypt = new WSEncryptBody(); encrypt.setUserInfo( "16c73ab6-b892-458f-abf5-2f875f74882e"); // build the encrypted SOAP part Document doc = unsignedEnvelope.getAsDocument(); Document encryptedDoc = encrypt.build(doc, crypto); // Convert the document into a SOAP message Message encryptedMsg = (Message)AxisUtil.toSOAPMessage(encryptedDoc); // Retrieve the desired SOAP part String soapPart = encryptedMsg.getSOAPPartAsString(); ((SOAPPart)axisMessage.getSOAPPart()). setCurrentMessage(soapPart, SOAPPart.FORM_STRING); encryptedDoc = axisMessage.getSOAPEnvelope().getAsDocument(); // Convert the document into a SOAP message Message encryptedSOAPMsg = (Message)AxisUtil.toSOAPMessage(encryptedDoc); return encryptedSOAPMsg; }

The SOAP envelope contained within the Axis message returned from the preceding method will look like Listing 4.

The "main" Method
Finally, a main method drives the methods defined above to sign, add username tokens to, and encrypt a SOAP envelope.

public static void main(String[] args) { try { WSSecuritySample app = new WSSecuritySample(); Message axisMessage = app.getAxisMessage(soapMsg); SOAPEnvelope unsignedEnvelope = axisMessage.getSOAPEnvelope(); System.out.println( "<<< Unsigned and Unencrypted >>>"); XMLUtils.PrettyElementToWriter( unsignedEnvelope.getAsDOM(), new PrintWriter(System.out)); Message samlMsg = app.addUserTokens(unsignedEnvelope); System.out.println("\n<<< User Tokens >>>"); XMLUtils.PrettyElementToWriter( samlMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out)); Message encryptedMsg = app.encryptSOAPEnvelope( unsignedEnvelope, axisMessage); System.out.println("\n<<< Encrypted >>>"); XMLUtils.PrettyElementToWriter( encryptedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out)); Message signedMsg = app.signSOAPEnvelope(unsignedEnvelope); System.out.println("\n<<< Signed >>>"); XMLUtils.PrettyElementToWriter( signedMsg.getSOAPEnvelope().getAsDOM(), new PrintWriter(System.out)); } catch (Exception e) { e.printStackTrace(); } }

Although the process may initially seem complex, a method such as the main method shown above simplifies the process considerably, breaking it down neatly into just a few steps: creating a SOAP envelope, and then signing, encrypting, and adding username tokens to it. I urge you to download the sample code for this article and experiment with the process. The WSS4J framework provides the core methods you need to meet the WS-Security specifications.



Jeff Hanson has more than 18 years of experience in the software industry. He has worked as senior engineer for the Windows OpenDoc port and as lead architect for the Route 66 framework at Novell. He is currently Chief Architect for eReinsure, which specializes in providing frameworks and platforms for J2EE-based reinsurance systems. Jeff has also authored numerous articles and books.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap