JBossWS - Stack CXF User Guide

The documentation below is meant for JBossWS 3.x series. Please refer http://www.jboss.org/jbossws/docs for links to other versions.

 

 

This page covers features available in JBossWS CXF stack only. Please refer to the common user guide for a basic introduction to JAX-WS programming as well as documentation on all features, tools, etc. the JBossWS Web Service Framework provides for every supported stack (including CXF stack).

 

Also please note this page does not go through the documentation of every feature, option, etc. provided by Apache CXF; on the countrary the only topics covered here are specific issues regarding integration with JBoss and stack specific features provided by JBossWS Web Service Framework for the CXF stack. A few tutorials are also provided for show how to leverage some WS technologies.

The official Apache CXF documentation is available here.

 

JBossWS CXF Integration

JBossWS-CXF integration layer is mainly meant for:

  • allowing using standard webservices APIs (including JAX-WS) as well as JBossWS stack independent APIs; this is performed internally leveraging Apache CXF without requiring the user to deal with it;
  • allowing using Apache CXF advanced features (including WS-*) on top of JBoss Application server without requiring the user to deal with / setup / care about the required integration steps for running in such a container.

In order for achieving the goals above, the JBossWS-CXF integration supports the JBossWS stack independent endpoint deployment (basically allowing users to deploy their JAX-WS endpoint application the exactly the same way they do with other JBossWS integration stacks) and comes with many internal customizations on top of Apache CXF.

Creating a Bus instance

Since 3.4.0

Most of the Apache CXF features are configurable using the org.apache.cxf.Bus class. While for basic JAX-WS usage the user might never need to explicitly deal with Bus, using Apache CXF specific features generally requires getting a handle to a org.apache.cxf.Bus instance. This can happen on client side as well as in a ws endpoint or handler business code.

New Bus instances are produced by the currently configured org.apache.cxf.BusFactory implementation the following way:

Bus bus = BusFactory.newInstance().createBus();

The algorithm for selecting the actual implementation of BusFactory to be used leverages the Service API, basically looking for optional configurations in META-INF/services/... location using the current thread context classloader. JBossWS-CXF integration comes with his own implementation of BusFactory, org.jboss.wsf.stack.cxf.client.configuration.JBossWSBusFactory, that allows for automatic detection of Spring availability as well as seamless setup of JBossWS customizations on top of Apache CXF. So, assuming the JBossWS-CXF libraries are available in the current thread context classloader, the JBossWSBusFactory is automatically retrieved by the BusFactory.newInstance() call above.

 

JBossWS users willing to explicitely use functionalities of org.apache.cxf.bus.spring.SpringBusFactory or org.apache.cxf.bus.CXFBusFactory, get the same API with JBossWS additions through JBossWSBusFactory:

String myConfigFile = ...
Bus bus = new JBossWSBusFactory().createBus(myConfigFile);

 

Map<Class, Object> myExtensions = new HashMap<Class, Object>();
myExtensions.put(...);
Bus bus = new JBossWSBusFactory().createBus(myExtensions);

Using existing Bus instances

Apache CXF keeps reference to a global default Bus instance as well as to a thread default bus for each thread. That is performed through static members in org.apache.cxf.BusFactory, which also comes with the following methods in the public API:

 

public static synchronized Bus getDefaultBus()
public static synchronized Bus getDefaultBus(boolean createIfNeeded)
public static synchronized void setDefaultBus(Bus bus)
public static Bus getThreadDefaultBus()
public static Bus getThreadDefaultBus(boolean createIfNeeded)
public static void setThreadDefaultBus(Bus bus)

 

Please note that the default behaviour of getDefaultBus() / getDefaultBus(true) / getThreadDefaultBus() / getThreadDefaultBus(true) is to create a new Bus instance if that's not set yet. Moreover getThreadDefaultBus() and getThreadDefaultBus(true) first fallback to retrieving the configured global default bus before actually trying creating a new instance (and the created new instance is set as global default bus if that was not there set yet).

The drawback of this mechanism (which is basically fine in JSE environment) is that when running in a JBoss AS container you need to be careful in order not to (mis)use a bus over multiple applications (assuming the Apache CXF classes are loaded by the same classloader, which is currently the case with AS6 and 7).

Here is a list of general suggestions to avoid problems when running in-container:

  • forget about the global default bus; you don't need that, so don't do getDefaultBus() / getDefaultBus(true) / setDefaultBus() in your code;
  • avoid getThreadDefaultBus() / getThreadDefaultBus(true) unless you already know for sure the default bus is already set;
  • keep in mind thread pooling whenever you customize a thread default bus instance (for instance adding bus scope interceptors, ...), as that thread and bus might be later reused; so either shutdown the bus when you're done or explicitly remove it from the BusFactory thread association.

Finally, remember that each time you explictly create a new Bus instance (factory.createBus()) that is set as thread default bus and global default bus if those are not set yet. The JAXWS Provider implementation also creates Bus instances internally, in particular the JBossWS version of JAXWS Provider makes sure the default bus is never internally used and instead a new Bus is created if required.

Server Side Integration Customization

The JBossWS-CXF server side integration takes care of internally creating proper Apache CXF structures (including a Bus instance, of course) for the ws endpoint deployment.

It is possible to customize the JBossWS and CXF integration by incorporating the CXF configuration file to the endpoint deployment archive. In order for that to be possible, JBossWS-CXF requires Spring to be installed in the application server. The Spring Framework libraries installation can be perfomed using the JBossWS-CXF installation.

The convention is the following:

  • file name must be jbossws-cxf.xml
  • for POJO deployments it is located in WEB-INF directory
  • for EJB3 deployments it is located in META-INF directory

If user do not provide its own CXF configuration file, a default one is automatically generated during the deployment.

For POJO deployments the generated jbossws-cxf.xml has the following content:

<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  xsi:schemaLocation='http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://cxf.apache.org/jaxws
  http://cxf.apache.org/schemas/jaxws.xsd'>

  <!-- one or more jaxws:endpoint POJO declarations -->
  <jaxws:endpoint
    id='POJOEndpoint'
    address='http://localhost:8080/pojo_endpoint_archive_name'  
    implementor='my.package.POJOEndpointImpl'>
    <jaxws:invoker>
      <bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/>
    </jaxws:invoker>
  </jaxws:endpoint>

</beans>

For EJB3 deployments the generated jbossws-cxf.xml has the following content:

<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  xsi:schemaLocation='http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://cxf.apache.org/jaxws
  http://cxf.apache.org/schemas/jaxws.xsd'>

  <!-- one or more jaxws:endpoint EJB3 declarations -->
  <jaxws:endpoint
    id='EJB3Endpoint'
    address='http://localhost:8080/ejb3_endpoint_archive_name'  
    implementor='my.package.EJB3EndpointImpl'>
    <jaxws:invoker>
      <bean class='org.jboss.wsf.stack.cxf.InvokerEJB3'/>
    </jaxws:invoker>
  </jaxws:endpoint>

</beans>

Providing custom CXF configuration to the endpoint deployment is useful in cases when users want to use features that are not part of standard JAX-WS specification but CXF implements them. For example see CXF WS-RM tutorial customization file. We are providing custom CXF endpoint configuration there to turn on WS-RM feature for endpoint.

Note

When user incorporates its own CXF configuration to the endpoint archive he must reference either org.jboss.wsf.stack.cxf.InvokerJSE or org.jboss.wsf.stack.cxf.InvokerEJB3 jaxws invoker bean there for each jaxws endpoint.

 

Please also consider that from a technical point of view, the jbossws-cxf.xml configuration file is basically treated as an addition to the default Apache CXF / JBossWS-CXF configuration. Hence users should be careful when dealing with global configurations (eg. global bus level interceptors) and instead provide those configuration in the deployment in another cxf.xml descriptor, which will be loaded at the same time as the default setup.

Extended Features

Here is the CXF documentation about supported WS-* specifications.

 

WS-Addressing

Apache CXF has a thorough support for WS-Addressing; details are available at the following pages:

CXF WS-Addressing documentation
CXF WS-Addressing configuration

 

Given the JAXWS specification currently covers WS-Addressing basic fuctionalities, users simply needing to enable it can make use of the @Addressing annotation and AddressingFeature, as shown in the following JBossWS-CXF tutorial:

JBossWS-CXF WS-Addressing Tutorial

 

WS-ReliableMessaging

The Apache CXF technical documentation on WS-RealiableMessaging is available as a reference at the following pages:

CXF WS-ReliableMessaging documentation
CXF WS-ReliableMessaging configuration

 

For a complete tutorial on how to enable WS-ReliableMessaging in a user client-server application, please take a look at:

JBossWS-CXF WS-ReliableMessaging Tutorial

 

WS-Policy

Apache CXF technical documentation on the WS-Policy engine and its configuration is available at:

CXF WS-Policy documentation
CXF WS-Policy configuration

 

For a complete sample of WS-Policy usage, please take a look at the JBossWS-CXF WS-ReliableMessaging tutorial below, as WS-RM is implemented leveraging policies there:

JBossWS-CXF WS-Policy & WS-ReliableMessaging Tutorial

 

Note on PolicyEngine setup

Since 3.4.0

When building up the Bus without Spring libraries available on the classpath, JBossWSBusFactory still makes sure the PolicyEngine (as well as the RMManager) is properly setup. This allows users to leverage basic WS-Policy functionalities the same way they'd do with a full Spring-enabled Bus.

 

WS-Security

Apache CXF leverages WSS4J to provide WS-Security functionalities. This means that thanks to the JBossWS-CXF integration, users can create web service applications using CXF - WSS4J implementation of WS-Security and deploy them on JBoss Application Server.

 

WSS4J security on JBoss

The Apache CXF documentation features an brief chapter on how to use WSS4J security in CXF. Here below instead you'll find some explanations on how to create a simple application and what you need to do to leverage WSS4J security on JBoss.

 

Creating the web service endpoint

First of all you need to create the web service endpoint / client using JAX-WS. This can be achieved in many ways, for instance you might want to:

  1. write your endpoint implementation, then run the wsprovide JBoss commandline tool which generates the service contract (bottom-up approach);
  2. run the wsconsume JBoss commandline tool to get the client artifacts from the service contract (top-down approach);
  3. write your client implementation.

 

Turn on WS-Security

WSS4J security is triggered through interceptors that are added to the service and/or client. These interceptors allows you to perform the most common WS-Security related process:

  • pass authentication tokens between services;
  • encrypt messages or parts of messages;
  • sign messages;
  • timestamp messages.

Interceptors can be added either programmatically or through the Spring xml configuration of endpoints.

For instance, on server side, you can configure signature and encryption in the jbossws-cxf.xml file this way:

<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  xsi:schemaLocation='http://cxf.apache.org/core
    http://cxf.apache.org/schemas/core.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://cxf.apache.org/jaxws
    http://cxf.apache.org/schemas/jaxws.xsd'>
  
  <bean id="Sign_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="Timestamp Signature Encrypt"/>
        <entry key="signaturePropFile" value="bob.properties"/>
        <entry key="decryptionPropFile" value="bob.properties"/>
        <entry key="passwordCallbackClass" value="org.jboss.test.ws.jaxws.samples.wsse.KeystorePasswordCallback"/>
      </map>
    </constructor-arg>
  </bean>
  
  <bean id="Sign_Response" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="Timestamp Signature Encrypt"/>
        <entry key="user" value="bob"/>
        <entry key="signaturePropFile" value="bob.properties"/>
        <entry key="encryptionPropFile" value="bob.properties"/>
        <entry key="encryptionUser" value="Alice"/>
        <entry key="signatureKeyIdentifier" value="DirectReference"/>
        <entry key="passwordCallbackClass" value="org.jboss.test.ws.jaxws.samples.wsse.KeystorePasswordCallback"/>
        <entry key="signatureParts" value="{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
        <entry key="encryptionParts" value="{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body"/>
        <entry key="encryptionKeyTransportAlgorithm" value="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <entry key="encryptionSymAlgorithm" value="http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/>
      </map>
    </constructor-arg>
  </bean>
  
  <jaxws:endpoint
    id='ServiceImpl'
    address='http://@jboss.bind.address@:8080/jaxws-samples-wsse-sign-encrypt'
    implementor='org.jboss.test.ws.jaxws.samples.wsse.ServiceImpl'>
    <jaxws:invoker>
      <bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/>
    </jaxws:invoker>
    <jaxws:outInterceptors>
        <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"/>
        <ref bean="Sign_Response"/>
    </jaxws:outInterceptors>
    <jaxws:inInterceptors>
        <ref bean="Sign_Request"/>
        <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
    </jaxws:inInterceptors>
  </jaxws:endpoint>
</beans>

This specifies the whole security configuration (including algorithms and elements to be signed/encrypted); moreover it references a properties file (bob.properties) providing the keystore-related information:

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=password
org.apache.ws.security.crypto.merlin.keystore.alias=bob
org.apache.ws.security.crypto.merlin.file=bob.jks

As you can see in the jbossws-cxf.xml file above, a keystore password callback handler is also configured; while the properties file has the password for the keystore, this callback handler is used to set password for each key (it has to match the one used when each key was imported in the store). Here's a trivial example:

package org.jboss.test.ws.jaxws.samples.wsse;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;

public class KeystorePasswordCallback implements CallbackHandler
{
   private Map<String, String> passwords = new HashMap<String, String>();

   public KeystorePasswordCallback()
   {
      passwords.put("alice", "password");
      passwords.put("bob", "password");
   }

   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
   {
      for (int i = 0; i < callbacks.length; i++)
      {
         WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
         String pass = passwords.get(pc.getIdentifer());
         if (pass != null)
         {
            pc.setPassword(pass);
            return;
         }
      }
   }

   public void setAliasPassword(String alias, String password)
   {
      passwords.put(alias, password);
   }
}

On client side, you can similarly setup the interceptors programmatically; here is an excerpt of the client for the above described endpoint (of course you can also leverage a proper Spring configuration for loading an already configured CXF Bus instance):

Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put("action", "Timestamp Signature Encrypt");
outProps.put("user", "alice");
outProps.put("signaturePropFile", "META-INF/alice.properties");
outProps.put("signatureKeyIdentifier", "DirectReference");
outProps.put("passwordCallbackClass", "org.jboss.test.ws.jaxws.samples.wsse.KeystorePasswordCallback");
outProps.put("signatureParts", "{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{http://schemas.xmlsoap.org/soap/envelope/}Body");
outProps.put("encryptionPropFile", "META-INF/alice.properties");
outProps.put("encryptionUser", "Bob");
outProps.put("encryptionParts", "{Element}{http://www.w3.org/2000/09/xmldsig#}Signature;{Content}{http://schemas.xmlsoap.org/soap/envelope/}Body");
outProps.put("encryptionSymAlgorithm", "http://www.w3.org/2001/04/xmlenc#tripledes-cbc");
outProps.put("encryptionKeyTransportAlgorithm", "http://www.w3.org/2001/04/xmlenc#rsa-1_5");
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps); //request
cxfEndpoint.getOutInterceptors().add(wssOut);
cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor());
      
Map<String,Object> inProps= new HashMap<String,Object>();
inProps.put("action", "Timestamp Signature Encrypt");
inProps.put("signaturePropFile", "META-INF/alice.properties");
inProps.put("passwordCallbackClass", "org.jboss.test.ws.jaxws.samples.wsse.KeystorePasswordCallback");
inProps.put("decryptionPropFile", "META-INF/alice.properties");
WSS4JInInterceptor wssIn = new WSS4JInInterceptor(inProps); //response
cxfEndpoint.getInInterceptors().add(wssIn);
cxfEndpoint.getInInterceptors().add(new SAAJInInterceptor());

Package and deploy

To deploy your web service endpoint, you need to package the following files along with your service implementation and wsdl contract:

  • the jbossws-cxf.xml descriptor
  • the properties file
  • the keystore file (if required for signature/encryption)
  • the keystore password callback handler class

For instance, here are the archive contents for the afore mentioned signature & encryption sample (POJO endpoint):

[alessio@localhost cxf-tests]$ jar -tvf target/test-libs/jaxws-samples-wsse-sign-encrypt.war 
   0 Tue Jun 03 19:41:26 CEST 2008 META-INF/
 106 Tue Jun 03 19:41:24 CEST 2008 META-INF/MANIFEST.MF
   0 Tue Jun 03 19:41:26 CEST 2008 WEB-INF/
   0 Tue Jun 03 19:41:26 CEST 2008 WEB-INF/classes/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
1628 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/KeystorePasswordCallback.class
 364 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/ServiceIface.class
 859 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/ServiceImpl.class
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/jaxws/
 685 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/jaxws/SayHello.class
1049 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/jaxws/SayHelloResponse.class
2847 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/jbossws-cxf.xml
   0 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/wsdl/
1575 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/wsdl/SecurityService.wsdl
 641 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/wsdl/SecurityService_schema1.xsd
1820 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/bob.jks
 311 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/classes/bob.properties
 573 Tue Jun 03 19:41:24 CEST 2008 WEB-INF/web.xml

On client side, instead, you only need the properties and keystore files (assuming you setup the interceptors programmatically).

Check that JBossWS-CXF is installed on your current JBoss Application Server, deploy and test your WS-Security-enabled application.

 

WS-Security Policies

 

Starting from JBossWS-CXF 3.1.1, WS-Security Policy implementation is available and can be used to configure WS-Security more easily.

Please refer to the Apache CXF documentation; basically instead of manually configuring interceptors in the client or through jbossws-cxf.xml descriptor, you simply provide the right policies in the WSDL contract.

  ...
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#SecurityServiceSignPolicy"/>
  ...
  <wsp:Policy wsu:Id="SecurityServiceSignPolicy"
    xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:AsymmetricBinding xmlns:sp='http://schemas.xmlsoap.org/ws/2005/07/securitypolicy'>
                <wsp:Policy>
                    <sp:InitiatorToken>
                        <wsp:Policy>
                            <sp:X509Token sp:IncludeToken='http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient'>
                                <wsp:Policy>
                                    <sp:WssX509V3Token10 />
                                </wsp:Policy>
                            </sp:X509Token>
                        </wsp:Policy>
                    </sp:InitiatorToken>
                    <sp:RecipientToken>
                        <wsp:Policy>
                            <sp:X509Token sp:IncludeToken='http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always'>
                                <wsp:Policy>
                                    <sp:WssX509V3Token10 />
                                </wsp:Policy>
                            </sp:X509Token>
                        </wsp:Policy>
                    </sp:RecipientToken>
                    <sp:AlgorithmSuite>
                        <wsp:Policy>
                            <sp:Basic256 />
                        </wsp:Policy>
                    </sp:AlgorithmSuite>
                    <sp:Layout>
                        <wsp:Policy>
                            <sp:Strict />
                        </wsp:Policy>
                    </sp:Layout>
                    <sp:OnlySignEntireHeadersAndBody />
                </wsp:Policy>
            </sp:AsymmetricBinding>
            <sp:Wss10 xmlns:sp='http://schemas.xmlsoap.org/ws/2005/07/securitypolicy'>
                <wsp:Policy>
                    <sp:MustSupportRefEmbeddedToken />
                </wsp:Policy>
            </sp:Wss10>
            <sp:SignedParts xmlns:sp='http://schemas.xmlsoap.org/ws/2005/07/securitypolicy'>
                <sp:Body />
            </sp:SignedParts>
        </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
  ...

Just few properties are also required to be set either in the message context or in the jbossws-cxf.xml descriptor.

((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER, new KeystorePasswordCallback());
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_PROPERTIES, Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties"));
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_PROPERTIES, Thread.currentThread().getContextClassLoader().getResource("META-INF/alice.properties"));
<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  xsi:schemaLocation='http://cxf.apache.org/core
    http://cxf.apache.org/schemas/core.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://cxf.apache.org/jaxws
    http://cxf.apache.org/schemas/jaxws.xsd'>
  
  <jaxws:endpoint
    id='ServiceImpl'
    address='http://@jboss.bind.address@:8080/jaxws-samples-wssePolicy-sign'
    implementor='org.jboss.test.ws.jaxws.samples.wssePolicy.ServiceImpl'>
    
    <jaxws:properties>
       <entry key="ws-security.signature.properties" value="bob.properties"/>
       <entry key="ws-security.encryption.properties" value="bob.properties"/>
       <entry key="ws-security.callback-handler" value="org.jboss.test.ws.jaxws.samples.wssePolicy.KeystorePasswordCallback"/>
    </jaxws:properties>
  </jaxws:endpoint>
</beans>

 

Authentication and authorization

 

The Username Token Profile can of course be used to provide client's credentials to the target endpoint. Starting from JBossWS-CXF 3.3.0 (which includes Apache CXF 2.2.8), the username token information can be used for authentication and authorization on JBoss AS (JAAS integration).

On server side, you need to specify what follows (for instance using a jbossws-cxf.xml descriptor):

  • an interceptor for performing authentication and populating a valid SecurityContext; the provided interceptor should extend org.apache.cxf.ws.security.wss4j.AbstractUsernameTokenAuthenticatingInterceptor, in particular JBossWS integration comes with org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor for this;
  • an interceptor for performing authorization; CXF requires that to extend org.apache.cxf.interceptor.security.AbstractAuthorizingInInterceptor, for instance the SimpleAuthorizingInterceptor can be used for simply mapping endpoint operations to allowed roles.
<beans
  xmlns='http://www.springframework.org/schema/beans'
  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
  xmlns:beans='http://www.springframework.org/schema/beans'
  xmlns:jaxws='http://cxf.apache.org/jaxws'
  xmlns:util='http://www.springframework.org/schema/util'
  xsi:schemaLocation='http://cxf.apache.org/core
    http://cxf.apache.org/schemas/core.xsd
    http://www.springframework.org/schema/util
    http://www.springframework.org/schema/util/spring-util-2.0.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://cxf.apache.org/jaxws
    http://cxf.apache.org/schemas/jaxws.xsd'>
  
  <bean id="SecurityContextIn"
     class="org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="UsernameToken"/> 
      </map>
    </constructor-arg>
  </bean>
 
  <util:map id="methodPermissions">
     <entry key="sayHello" value="friend"/> 
     <entry key="greetMe" value="snoopies"/> 
  </util:map>
 
  <bean id="AuthorizeIn"
    class="org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor">
   <property name="methodRolesMap" ref="methodPermissions"/> 
  </bean>
  
  <jaxws:endpoint
    id='ServiceImpl'
    address='http://@jboss.bind.address@:8080/jaxws-samples-wsse-username-authorize'
    implementor='org.jboss.test.ws.jaxws.samples.wsse.ServiceImpl'>
    <jaxws:inInterceptors>
        <ref bean="SecurityContextIn"/>
        <ref bean="AuthorizeIn"/>
        <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor"/>
    </jaxws:inInterceptors>
  </jaxws:endpoint>
</beans>

 

Authentication and authorization will simply be delegated to the security domain configured for the endpoint. Of course you can specify the login module you prefer for that security domain (refer the application server / security documentation for that).

 

On client side, the username is provided through API (or a custom Spring configuration used to load the Bus):

 

Endpoint cxfEndpoint = client.getEndpoint();
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put("action", "UsernameToken");
outProps.put("user", username);
outProps.put("passwordType", "PasswordText");
outProps.put("passwordCallbackClass", "org.jboss.test.ws.jaxws.samples.wsse.UsernamePasswordCallback");
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps); //request
cxfEndpoint.getOutInterceptors().add(wssOut);
cxfEndpoint.getOutInterceptors().add(new SAAJOutInterceptor());

 

The password instead is provided through a password callback handler that needs to implement javax.security.auth.callback.CallbackHandler, similarly to the keystore's password callback handler.

 

If you're running an older JBossWS-CXF version, or you're not interested in the the application server auth integration, you can use a password callback handler on server side too, configured through a WSS4JInInterceptor:

 

<bean id="UsernameToken_Request" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
  <constructor-arg>
    <map>
      <entry key="action" value="UsernameToken"/> 
      <entry key="passwordCallbackClass" value="org.jboss.test.ws.jaxws.samples.wsse.ServerUsernamePasswordCallback"/> 
    </map>
  </constructor-arg>
</bean>

 

package org.jboss.test.ws.jaxws.samples.wsse;

import java.io.IOException;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;

public class ServerUsernamePasswordCallback implements CallbackHandler
{
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
   {
      WSPasswordCallback pc = (WSPasswordCallback)callbacks[0];
      if (!("kermit".equals(pc.getIdentifier()) && "thefrog".equals(pc.getPassword())))
         throw new SecurityException("User '" + pc.getIdentifier() + "' with password '" + pc.getPassword() + "' not allowed.");
   }
}

Further information

Samples

The JBossWS-CXF source distribution comes with some samples using X.509 certificate signature and encryption as well as Username Token Profile. You can find them in package org.jboss.test.ws.jaxws.samples.wsse .

Crypto algorithms

When requiring encryption, you might need to install an additional JCE provider supporting the crypto algorithms Apache CXF uses. This usually means the Bouncy Castle provider need to be configured in your JRE. Please refer the Native stack user guide for further information about this.

 

JMS transport

Here is a tutorial on how to deploy and invoke a JMS endpoint using JBossWS-CXF.

 

HTTP server transport setup

Apache CXF comes with pluggable transport layers, allowing different transport modules to be used.

 

The JBossWS-CXF integration leverages CXF servlet transport for the deployment of endpoints on top of the running JBoss Application Server.

 

However, when users directly leverage the JAXWS Endpoint.publish(String s) API, endpoints are expected to be deployed on a standalone http server started just for serving the specified endpoint. Apache CXF currently defaults to using the Jetty based http transport. Starting from release 3.4.0, the JBossWS-CXF integration instead uses a different http transport module based on the http server embedded in JDK6 distributions. Thanks to Apache CXF transport pluggability, users can still change the transport they want to use in this case by simply replacing the jbossws-cxf-transports-httpserver.jar library with another http transport one, for instance the cxf-rt-transports-http-jetty.jar.

 

SOAP Message Logging

In the jbossws-cxf-client.jar[*] file you will find META-INF/cxf/cxf-extension-jbossws.xml, which contains the JBossWS extensions to the Apache CXF stack. In that file you need to enable

  <cxf:bus>
    <cxf:inInterceptors>
      <ref bean="logInbound"/>
    </cxf:inInterceptors>
    <cxf:outInterceptors>
      <ref bean="logOutbound"/>
    </cxf:outInterceptors>
    <cxf:inFaultInterceptors>
      <ref bean="logOutbound"/>
    </cxf:inFaultInterceptors>
  </cxf:bus>

 

Once you've uncommented the cxf-extension-jbossws.xml contents, you need to re-pack the jar/zip.

 

[*] The cxf-extension-jbossws.xml is available from version 3.2.2; if you don't have that file, you can manually add it and link it in cxf.extensions file.

 

Finally, please note that logging can be enabled in many ways with Apache CXF, see the following documentation pages for instance: