Web Services CXF User Guide
for use with JBoss Enterprise Application Platform 5
Edition 5.2.0
Alessio Soldano
Edited by
Elspeth Thorne
Edited by
Eva Kopalova
Edited by
Petr Penicka
Edited by
Rebecca Newton
Edited by
Russell Dickenson
Edited by
Scott Mumford
Abstract
Chapter 1. Introduction
- Web Services Standard Support
- CXF supports a variety of web service standards including:
- SOAP
- WSI Basic Profile.
- WSDL
- WS-Addressing
- WS-Policy
- WS-ReliableMessaging
- WS-Security
- WS-SecurityPolicy
- WS-SecureConversation
- Front ends
- CXF supports a variety of front-end programming models. CXF implements the JAX-WS APIs (TCK compliant). It also includes a simple front end which allows creation of clients and endpoints without annotations. CXF supports both contract first development with WSDL and code first development starting from Java.
- Ease of use
- CXF is designed to be intuitive and easy to use.
- There are simple APIs to quickly build code-first services.
- Maven plug-ins to make tooling integration easy.
- JAX-WS API support.
- Spring 2.x XML support to make configuration easier.
Chapter 2. Installation
Warning
Procedure 2.1. Installing CXF
Download the Installer
Download and unzip thejboss-ep-ws-cxf-5.1.0-installer.zip
in the home jboss-as directory directly under the Platform installation root.Replace WS Native with WS CXF
Runant
in the created directory,jbossws-cxf-installer
.
Note
http://localhost:8080/jbossws
Chapter 3. Server Side Integration Customization
- The 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
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>
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>
Note
org.jboss.wsf.stack.cxf.InvokerJSE
or the org.jboss.wsf.stack.cxf.InvokerEJB3 JAX-WS
invoker bean there for each JAX-WS endpoint.
Chapter 4. WS Addressing
4.1. Using JAX-WS for enabling WS-Addressing
package org.jboss.test.ws.jaxws.samples.wsa; import javax.jws.WebService; import javax.xml.ws.soap.Addressing; @WebService @Addressing(enabled=true, required=true) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Hello World!"; } }
org.apache.cxf.ws.addressing.WSAddressingFeature
when getting the proxy instance from the service:
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class, new AddressingFeature()); proxy.sayHello());
4.1.1. Using CXF proprietary WSAddressingFeature
<jaxws:endpoint id="{your.service.namespace}YourPortName"> <jaxws:features> <wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/> </jaxws:features> </jaxws:endpoint>
<jaxws:client id="{your.service.namespace}YourPortName"> <jaxws:features> <wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/> </jaxws:features> </jaxws:client>
Chapter 5. Addressing Tutorial
We will start with the following endpoint implementation.
package org.jboss.test.ws.jaxws.samples.wsa; import javax.jws.web service; @web service ( portName = "AddressingServicePort", serviceName = "AddressingService", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsa.ServiceIface" ) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Hello World!"; } }
package org.jboss.test.ws.jaxws.samples.wsa; import javax.jws.WebMethod; import javax.jws.web service; @web service ( targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing" ) public interface ServiceIface { @WebMethod String sayHello(); }
/home/username/wsa/cxf/classes
. The next step is to generate the JAX-WS artifacts and WSDL that will be part of the endpoint archive.
We will use the wsprovide
command line tool to generate WSDL and JAX-WS artifacts. Here's the command:
cd JBOSS_HOME/bin ./wsprovide.sh --keep --wsdl \ --classpath=/home/username/wsa/cxf/classes \ --output=/home/username/wsa/cxf/wsprovide/generated/classes \ --resource=/home/username/wsa/cxf/wsprovide/generated/wsdl \ --source=/home/username/wsa/cxf/wsprovide/generated/src \ org.jboss.test.ws.jaxws.samples.wsa.ServiceImpl
- Compiled classes
SayHello.class
SayHelloResponse.class
- Java Sources
SayHello.java
SayHelloResponse.java
- Contract Artifacts
AddressingService.wsdl
wsdlLocation
annotation attribute. This is the updated endpoint implementation before it is packaged to the war
file:
package org.jboss.test.ws.jaxws.samples.wsa; import javax.jws.web service; @web service ( portName = "AddressingServicePort", serviceName = "AddressingService", wsdlLocation = "WEB-INF/wsdl/AddressingService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsa.ServiceIface" ) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Hello World!"; } }
jar -tvf jaxws-samples-wsa.war 0 Mon Apr 21 20:39:30 CEST 2008 META-INF/ 106 Mon Apr 21 20:39:28 CEST 2008 META-INF/MANIFEST.MF 0 Mon Apr 21 20:39:30 CEST 2008 WEB-INF/ 593 Mon Apr 21 20:39:28 CEST 2008 WEB-INF/web.xml 0 Mon Apr 21 20:39:30 CEST 2008 WEB-INF/classes/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/ 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/ 374 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/ServiceIface.class 954 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/ServiceImpl.class 0 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/jaxws/ 703 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/jaxws/SayHello.class 1074 Mon Apr 21 20:39:26 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsa/jaxws/SayHelloResponse.class 0 Mon Apr 21 20:39:30 CEST 2008 WEB-INF/wsdl/ 2378 Mon Apr 21 20:39:28 CEST 2008 WEB-INF/wsdl/AddressingService.wsdl
web.xml
file is:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>AddressingService</servlet-name> <servlet-class>org.jboss.test.ws.jaxws.samples.wsa.ServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>AddressingService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
The following is the regular JAX-WS client using endpoint interface to lookup the web service: package.org.jboss.test.ws.jaxws.samples.wsa:
package.org.jboss.test.ws.jaxws.samples.wsa: import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; public final class SimpleServiceTestCase { private final String serviceURL = "http://localhost:8080/jaxws-samples-wsa/AddressingService"; public static void main(String[] args) throws Exception { // create service QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsaddressing", "AddressingService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class); // invoke method proxy.sayHello(); } }
5.1. Turning on WS-Addressing 1.0
- Annotate service endpoint with @Addressing annotation.
- Modify client to configure WS-Addressing using the JAX-WS web service feature.
Now we need to update endpoint implementation to configure WS-Addressing. Here's the updated endpoint code:
package org.jboss.test.ws.jaxws.samples.wsa; import javax.jws.web service; import javax.xml.ws.soap.Addressing; @web service ( portName = "AddressingServicePort", serviceName = "AddressingService", wsdlLocation = "WEB-INF/wsdl/AddressingService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsaddressing", endpointInterface = "org.jboss.test.ws.jaxws.samples.wsa.ServiceIface" ) @Addressing(enabled=true, required=true) public class ServiceImpl implements ServiceIface { public String sayHello() { return "Hello World!"; } }
We need to update client implementation to configure WS-Addressing. Here's the updated client code:
package org.jboss.test.ws.jaxws.samples.wsa; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import javax.xml.ws.soap.AddressingFeature; public final class AddressingTestCase { private final String serviceURL = "http://localhost:8080/jaxws-samples-wsa/AddressingService"; public static void main(String[] args) throws Exception { // construct proxy QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsaddressing", "AddressingService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class, new AddressingFeature()); // invoke method proxy.sayHello(); } }
Chapter 6. WS-Reliable Messaging
org.apache.cxf.ws.rm.RMOutInterceptor
- Responsible for:
- Sending
CreateSequence
requests. - Waiting for their
CreateSequenceResponse
responses. - Collecting the sequence properties (id and message number) for an application message.
-
org.apache.cxf.ws.rm.RMInInterceptor
- Intercepting and processing RM protocol messages, as well as
SequenceAcknowledgments
piggybacked on application messages. org.apache.cxf.ws.rm.soap.RMSoapInterceptor
- Encoding and decoding the RM headers
-
org.apache.cxf.ws.rm.soap.RetransmissionInterceptor
- Responsible for creating copies of application messages for future resends.
The presence of the RM interceptors on the respective interceptor chains alone will ensure that RM protocol messages are exchanged when necessary. For example, upon intercepting the first application message on the outbound interceptor chain, the RMOutInterceptor
will send a CreateSequence
request and only proceed with processing the original application message after it has the CreateSequenceResponse
response. The RM interceptors are also responsible for adding the sequence headers to the application messages and, on the destination side, extracting them from the message.
Chapter 7. Using WS-Reliable Messaging
The RM interceptors will be automatically added to their respective interceptor chains by the policy framework if the following occurs:
- A Policy with an RMAssertion element is attached to the
wsdl:service
element (or any other WSDL element that is an attachment point for Policy or PolicyReference elements according to the rules for WS-Policy Attachments). - The CXF WS-Policy Framework is enabled
<jaxws:endpoint ...> <jaxws:features> <p:policies/> </jaxws:features> </jaxws:endpoint>
<wsp:Policy wsu:Id="RM" xmlns:wsp="http://www.w3.org/2006/07/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsam:Addressing xmlns:wsam="http://www.w3.org/2007/02/addressing/metadata"> <wsp:Policy/> </wsam:Addressing> <wsrmp:RMAssertion xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"> <wsrmp:BaseRetransmissionInterval Milliseconds="10000"/> </wsrmp:RMAssertion> </wsp:Policy> ... <wsdl:service name="ReliableGreeterService"> <wsdl:port binding="tns:GreeterSOAPBinding" name="GreeterPort"> <soap:address location="http://localhost:9020/SoapContext/GreeterPort"/> <wsp:PolicyReference URI="#RM" xmlns:wsp="http://www.w3.org/2006/07/ws-policy"/> </wsdl:port> </wsdl:service>
wsdl:port
element, you can also specify it as a child element of the policies featured, such as the server endpoint.
<wsp:Policy wsu:Id="="RM" xmlns:wsp="http://www.w3.org/2006/07/ws-policy" ...> </wsp:Policy> <jaxws:endpoint ...> <jaxws:features> <p:policies> <wsp:PolicyReference URI="#RM" xmlns:wsp="http://www.w3.org/2006/07/ws-policy"/> </p:policies> </jaxws:features> </jaxws:endpoint>
You can use the ReliableMessaging feature if you do not want to involve the WS-Policy Framework, or want to configure additional parameters such as the sequence termination policy or the persistent store. The supported child elements are listed below.
- RMAssertion
- An element of type RMAssertion.
- deliveryAssurance
- An element of type DeliveryAssuranceType that describes the delivery assurance that should apply (
AtMostOnce
,AtLeastOnce
,InOrder
). - sourcePolicy
- An element of type SourcePolicyType that allows you to configure details of the RM source, such as whether an offer should always be included in a
CreateSequence
request, or the sequence termination policy. - destinationPolicy
- An element of type DestinationPolicyType that allows you to configure details of the RM destination, such as whether inbound offers should be accepted.
- store
- The store to use (default:
null
). This must be an element of type jdbcStore (in the same namespace), or a bean or a reference to a bean that implements the RMStore interface.
<cxf:bus> <cxf:features> <wsa:addressing/> <wsrm-mgr:reliableMessaging> <wsrm-policy:RMAssertion> <wsrm-policy:BaseRetransmissionInterval Milliseconds="4000"/> <wsrm-policy:AcknowledgementInterval Milliseconds="2000"/> </wsrm-policy:RMAssertion> <wsrm-mgr:sourcePolicy> <wsrm-mgr:sequenceTerminationPolicy maxLength="5"/> </wsrm-mgr:sourcePolicy> <wsrm-mgr:destinationPolicy acceptOffers="false"> <wsrm:store> <ref bean="myStore"/> </wsrm:store> </wsrm-mgr:reliableMessaging> </cxf:features> </cxf:bus>
To enable persistence, you must specify the object implementing the persistent store for RM. You can develop your own, or use the JDBC based store that comes with CXF (class org.apache.cxf.ws.rm.persistence.jdbc.RMTxStore
). You can configure the latter using a custom jdbcStore bean. The supported attributes are in the table below.
Table 7.1. Attributes
Attribute name | String | Default |
---|---|---|
driverClassName | String | org.apache.derby.jdbc.EmbeddedDriver |
userName | String | null |
passWord | String | null |
url | String | jdbc:derby:rmdb;create=true |
<wsrm-mgr:jdbcStore id="myStore" driverClassName="org.apache.derby.jdbc.ClientDriver" url="jdbc:derby://localhost:1527/rmdb;create=true" password="password"/>
To configure properties of the RM Manager, you can use the RMManager element. It supports the same child elements as the ReliableMessaging feature element above. For example, without using features, you can determine that sequences should have a maximum length of five as follows:
<wsrm-mgr:rmManager xmlns:wsrm-mgr="http://cxf.apache.org/ws/rm/manager"> <wsrm-mgr:sourcePolicy> <wsrm-mgr:sequenceTerminationPolicy maxLength="5"/> </wsrm-mgr:sourcePolicy> </wsrm-mgr:rmManager>
Chapter 8. WS-Reliable Messaging Tutorial
package org.jboss.test.ws.jaxws.samples.wsrm.service; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebService; @WebService ( name = "SimpleService", serviceName = "SimpleService", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsrm" ) public class SimpleServiceImpl { @Oneway @WebMethod public void ping() { System.out.println("ping()"); } @WebMethod public String echo(String s) { System.out.println("echo(" + s + ")"); return s; } }
/home/username/wsrm/cxf/classes
. Our next step is to generate JAX-WS artifacts and WSSDL.
8.1. Generating WSDL and JAX-WS Endpoint Artifacts
wsprovide
command line tool to generate WSDL and JAX-WS artifacts. Here's the command:
cd $JBOSS_HOME/bin ./wsprovide.sh --keep --wsdl \ --classpath=/home/username/wsrm/cxf/classes \ --output=/home/username/wsrm/cxf/wsprovide/generated/classes \ --resource=/home/username/wsrm/cxf/wsprovide/generated/wsdl \ --source=/home/username/wsrm/cxf/wsprovide/generated/src \ org.jboss.test.ws.jaxws.samples.wsrm.service.SimpleServiceImpl
- Compiled classes
- Echo.classEcho response.classPing.class
- Java sources
- Echo.javaEchoResponse.javaPing.java
- Contract artifacts
- SimpleService.wsdl
wsdlLocation
annotation attribute. Here's the updated endpoint implementation before it is packaged to the war
file:
package org.jboss.test.ws.jaxws.samples.wsrm.service; import javax.jws.Oneway; import javax.jws.WebMethod; import javax.jws.WebService; @WebService ( name = "SimpleService", serviceName = "SimpleService", wsdlLocation = "WEB-INF/wsdl/SimpleService.wsdl", targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wsrm" ) public class SimpleServiceImpl { @Oneway @WebMethod public void ping() { System.out.println("ping()"); } @WebMethod public String echo(String s) { System.out.println("echo(" + s + ")"); return s; } }
jar -tvf jaxws-samples-wsrm.war 0 Wed Apr 16 14:39:22 CEST 2008 META-INF/ 106 Wed Apr 16 14:39:20 CEST 2008 META-INF/MANIFEST.MF 0 Wed Apr 16 14:39:22 CEST 2008 WEB-INF/ 591 Wed Apr 16 14:39:20 CEST 2008 WEB-INF/web.xml 0 Wed Apr 16 14:39:22 CEST 2008 WEB-INF/classes/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/ 0 Wed Apr 16 14:39:20 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/ 0 Wed Apr 16 14:39:20 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/ 0 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/ 1235 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/SimpleServiceImpl.class 997 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/Echo.class 1050 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/EchoResponse.class 679 Wed Apr 16 14:39:18 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/Ping.class 0 Wed Apr 16 14:39:22 CEST 2008 WEB-INF/wsdl/ 2799 Wed Apr 16 14:39:20 CEST 2008 WEB-INF/wsdl/SimpleService.wsdl
web.xml
file is:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>SimpleService</servlet-name> <servlet-class>org.jboss.test.ws.jaxws.samples.wsrm.service.SimpleServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>SimpleService</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
8.2. Generating JAX-WS Client Artifacts
cd $JBOSS_HOME/bin ./wsconsume.sh --keep \ --package=org.jboss.test.ws.jaxws.samples.wsrm.generated \ --output=/home/username/wsrm/cxf/wsconsume/generated/classes \ --source=/home/username/wsrm/cxf/wsconsume/generated/src \ /home/username/wsrm/cxf/wsprovide/generated/wsdl/SimpleService.wsdl
- Compiled classes
- Echo.classObjectFactory.classPing.classSimpleService_Service.classEchoResponse.classpackage-info.classSimpleService.classSimpleService_SimpleServicePort_Client.class
- Java sources
- Echo.javaObjectFactory.javaPing.javaSimpleService_Service.javaEchoResponse.javapackage-info.javaSimpleService.javaSimpleService_SimpleServicePort_Client.java
The following is the regular JAX-WS client using generated artifacts:
package org.jboss.test.ws.jaxws.samples.wsrm.client; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Service; import org.jboss.test.ws.jaxws.samples.wsrm.generated.SimpleService; public final class SimpleServiceTestCase { private static final String serviceURL = "http://localhost:8080/jaxws-samples-wsrm/SimpleService"; public static void main(String[] args) throws Exception { // create service QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsrm", "SimpleService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); SimpleService proxy = (SimpleService)service.getPort(SimpleService.class); // invoke methods proxy.ping(); // one way call proxy.echo("Hello World!"); // request responce call } }
8.3. Turning on WS-RM 1.0
- Extend WSDL with WS-Policy containing both WSRM and WS-Addressing policy.
- Provide
jbossws-cxf.xml
endpoint configuration file. - Provide client CXF configuration.
- Update client code to read CXF configuration file.
To activate WSRM we need to extend WSDL with WSRM and addressing policy. Here is how it looks:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions name="SimpleService" targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wsrm" xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wsrm" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsp="http://www.w3.org/2006/07/ws-policy"> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - --> <!-- Created WS-Policy with WSRM addressing assertions --> <!-- - - - - - - - - - - - - - - - - - - - - - - - - - --> <wsp:UsingPolicy/> <wsp:Policy wsu:Id="wsrm10policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wswa:UsingAddressing xmlns:wswa="http://www.w3.org/2006/05/addressing/wsdl"> <wsp:Policy/> <wswa:UsingAddressing> <wsrmp:RMAssertion xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"/> </wsp:Policy> <wsdl:types> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wsrm" attributeFormDefault="unqualified" elementFormDefault="unqualified" targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wsrm"> <xsd:element name="ping" type="tns:ping"/> <xsd:complexType name="ping"> <xsd:sequence/> </xsd:complexType> <xsd:element name="echo" type="tns:echo"/> <xsd:complexType name="echo"> <xsd:sequence> <xsd:element minOccurs="0" name="arg0" type="xsd:string"/> </xsd:sequence> </xsd:complexType> <xsd:element name="echoResponse" type="tns:echoResponse"/> <xsd:complexType name="echoResponse"> <xsd:sequence> <xsd:element minOccurs="0" name="return" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="echoResponse"> <wsdl:part name="parameters" element="tns:echoResponse"> </wsdl:part> </wsdl:message> <wsdl:message name="echo"> <wsdl:part name="parameters" element="tns:echo"> </wsdl:part> </wsdl:message> <wsdl:message name="ping"> <wsdl:part name="parameters" element="tns:ping"> </wsdl:part> </wsdl:message> <wsdl:portType name="SimpleService"> <wsdl:operation name="ping"> <wsdl:input name="ping" message="tns:ping"> </wsdl:input> </wsdl:operation> <wsdl:operation name="echo"> <wsdl:input name="echo" message="tns:echo"> </wsdl:input> <wsdl:output name="echoResponse" message="tns:echoResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="SimpleServiceSoapBinding" type="tns:SimpleService"> <!-- - - - - - - - - - - - - - - - - - - - --> <!-- Associated WS-Policy with the binding --> <!-- - - - - - - - - - - - - - - - - - - - --> <wsp:PolicyReference URI="#wsrm10policy"/> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="ping"> <soap:operation soapAction="" style="document"/> <wsdl:input name="ping"> <soap:body use="literal"/> </wsdl:input> </wsdl:operation> <wsdl:operation name="echo"> <soap:operation soapAction="" style="document"/> <wsdl:input name="echo"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="echoResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="SimpleService"> <wsdl:port name="SimpleServicePort" binding="tns:SimpleServiceSoapBinding"> <soap:address location="http://localhost:9090/hello"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
wsp:UsingPolicy;
wsp:Policy
and wsp:PolicyReference
elements to WSDL.
jbossws-cxf.xml
Endpoint Configuration File This is the JBossWS CXF integration extension file: Chapter 3, Server Side Integration Customization . In our case, the relevant content is as follows:
<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:wsp='http://www.w3.org/2006/07/ws-policy' xmlns:p='http://cxf.apache.org/policy' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://www.w3.org/2006/07/ws-policy http://www.w3.org/2006/07/ws-policy.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd'> <wsp:Policy wsu:Id="wsrm10policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wswa:UsingAddressing xmlns:wswa="http://www.w3.org/2006/05/addressing/wsdl"/> <wsrmp:RMAssertion xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"/> </wsp:Policy> <jaxws:endpoint id='SimpleServiceImpl' address='http://localhost:8080/jaxws-samples-wsrm' implementor='org.jboss.test.ws.jaxws.samples.wsrm.service.SimpleServiceImpl'> <jaxws:invoker> <bean class='org.jboss.wsf.stack.cxf.InvokerJSE'/> </jaxws:invoker> <jaxws:features> <p:policies> <wsp:PolicyReference URI="#wsrm10policy" xmlns:wsp="http://www.w3.org/2006/07/ws-policy"/> </p:policies> </jaxws:features> </jaxws:endpoint> </beans>
jbossws-cxf.xml
CXF configuration file in the WEB-INF
directory of the endpoint archive because we are creating a POJO deployment.
jar -tvf jaxws-samples-wsrm.war 0 Wed Apr 16 19:05:38 CEST 2008 META-INF/ 106 Wed Apr 16 19:05:36 CEST 2008 META-INF/MANIFEST.MF 0 Wed Apr 16 19:05:38 CEST 2008 WEB-INF/ 591 Wed Apr 16 19:05:36 CEST 2008 WEB-INF/web.xml 0 Wed Apr 16 19:05:38 CEST 2008 WEB-INF/classes/ 0 Wed Apr 16 19:05:32 CEST 2008 WEB-INF/classes/org/ 0 Wed Apr 16 19:05:32 CEST 2008 WEB-INF/classes/org/jboss/ 0 Wed Apr 16 19:05:32 CEST 2008 WEB-INF/classes/org/jboss/test/ 0 Wed Apr 16 19:05:32 CEST 2008 WEB-INF/classes/org/jboss/test/ws/ 0 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/ 0 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/ 0 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/ 0 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/ 0 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/ 1235 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/SimpleServiceImpl.class 997 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/Echo.class 1050 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/EchoResponse.class 679 Wed Apr 16 19:05:34 CEST 2008 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsrm/service/jaxws/Ping.class 1554 Wed Apr 16 19:05:36 CEST 2008 WEB-INF/jbossws-cxf.xml 0 Wed Apr 16 19:05:38 CEST 2008 WEB-INF/wsdl/ 3237 Wed Apr 16 19:05:36 CEST 2008 WEB-INF/wsdl/SimpleService.wsdl
cxf.xml
in our sample. The content of this file is as follows:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core" xmlns:wsa="http://cxf.apache.org/ws/addressing" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:wsrm-policy="http://schemas.xmlsoap.org/ws/2005/02/rm/policy" xmlns:wsrm-mgr="http://cxf.apache.org/ws/rm/manager" xsi:schemaLocation=" http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd http://schemas.xmlsoap.org/ws/2005/02/rm/policy http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm-policy.xsd http://cxf.apache.org/ws/rm/manager http://cxf.apache.org/schemas/configuration/wsrm-manager.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <cxf:bus> <cxf:features> <cxf:logging/> <wsa:addressing/> <wsrm-mgr:reliableMessaging> <wsrm-policy:RMAssertion> <wsrm-policy:BaseRetransmissionInterval Milliseconds="4000"/> <wsrm-policy:AcknowledgementInterval Milliseconds="2000"/> </wsrm-policy:RMAssertion> <wsrm-mgr:destinationPolicy> <wsrm-mgr:acksPolicy intraMessageThreshold="0" /> </wsrm-mgr:destinationPolicy> </wsrm-mgr:reliableMessaging> </cxf:features> </cxf:bus> </beans>
cxf.xml
has to be put in the META-INF
directory of client jar. That jar should then be provided when setting the class loader.
Here's the last piece of the updated CXF client:
package org.jboss.test.ws.jaxws.samples.wsrm.client; import java.net.URL; import java.io.File; import javax.xml.namespace.QName; import javax.xml.ws.Service; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.bus.spring.SpringBusFactory; import org.jboss.test.ws.jaxws.samples.wsrm.generated.SimpleService; public final class SimpleServiceTestCase { private static final String serviceURL = "http://localhost:8080/jaxws-samples-wsrm/SimpleService"; public static void main(String[] args) throws Exception { // create bus SpringBusFactory busFactory = new SpringBusFactory(); URL cxfConfig = new File("resources/jaxws/samples/wsrm/cxf.xml").toURL(); Bus bus = busFactory.createBus(cxfConfig); busFactory.setDefaultBus(bus); // create service QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsrm", "SimpleService"); URL wsdlURL = new URL(serviceURL + "?wsdl"); Service service = Service.create(wsdlURL, serviceName); SimpleService proxy = (SimpleService)service.getPort(SimpleService.class); // invoke methods proxy.ping(); // one way call proxy.echo("Hello World!"); // request responce call // shutdown bus bus.shutdown(true); } }
Chapter 9. WS Policy Framework
9.1. Using The Policies Feature
- ignoreUnknownAssertions
- Indicates an exception should be thrown when encountering assertions for which no AssertionBuilders are registered (default:
true
). When set to false, a warning will be logged instead. - namespace
- The namespace of the WS-Policy Framework specification (default: http://www.w3.org/ns/ws-policy).
- alternativeSelector
- A bean or reference to a bean that implements the
org.apache.cxf.ws.policy.selector.AlternativeSelector
interface. The default selector chooses the minimal alternative; that is, the one with the least number of assertions.
wsdl:port
element of the WSDL contract of the client or server endpoint to which the feature is applied (or to all endpoints if the feature is applied to the bus).
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://cxf.apache.org/policy http://cxf.apache.org/schemas/policy.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <cxf:bus> <cxf:features> <p:policies ignoreUnknownAssertions="true"/> </cxf:features> </cxf:bus> </beans>
9.2. Specifying the Location of External Attachments
<externalAttachment>
element in the same namespace. The following attribute is supported.
- location
- Location of the external attachment document. This takes the form of http://static.springsource.org/spring/docs/2.0.x/reference/resources.html type property, for example,
classpath:etc/policies.xml
orfile:///x1/resources/polcies.xml
.
<p:externalAttachment location="classpath:org/apache/cxf/systest/ws/policy/addr-external.xml"/>
<externalAttachment>
elements in your configuration file.
Chapter 10. WS-Security
HTTPS
. Through a number of standards such as XML-Encryption, and headers defined in the WS-Security standard, it allows you to:
- Pass authentication tokens between services.
- Encrypt messages or parts of messages.
- Sign messages.
- Timestamp messages.
10.1. Overview of Encryption and Signing
Chapter 11. WSS4J security on JBoss
11.1. Creating the web service endpoint
- Write your endpoint implementation, then run the
wsprovide
JBoss command line tool which generates the service contract. - Run the
wsconsume
JBoss command line tool to get the client artifacts from the service contract (top-down approach). - Write your client implementation.
11.2. Turn on WS-Security
- Pass authentication tokens between services.
- Encrypt messages or parts of messages.
- Sign messages.
- Timestamp messages.
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>
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
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 is an 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); } }
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());
11.2.1. Package and deploy
- The
jbossws-cxf.xml
descriptor. - The properties file.
- The keystore file (if required for signature/encryption).
- The keystore password callback handler class.
[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
11.3. WS-Security Policies
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> ...
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>
11.4. Authentication
Task: Authenticate a Web Service User
Task Summary
Secure access to the Stateless Session Bean
Secure access to the Stateless Session Bean (SLSB) using the@RolesAllowed
,@PermitAll
,@DenyAll
annotations.The allowed user roles can be set with these annotations both on the bean class and on any of its business methods.@Stateless @RolesAllowed("friend") public class EndpointEJB implements EndpointInterface { ... }
Secure POJO endpoints
Secure Plain Old Java Object (POJO) endpoints by defining a <security-constraint> in theWEB-INF/web.xml
file of the application. The <auth-constraint> <role-name> element specifies whether authentication is mandatory. It can be set to "not required" by specifying an asterisk value in the <role-name> element.<security-constraint> <web-resource-collection> <web-resource-name>All resources</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>friend</role-name> </auth-constraint> </security-constraint> <security-role> <role-name>friend</role-name> </security-role>
Define the security domain for EJB3 endpoints
Declare the security domain by appending the @SecurityDomain annotation@Stateless @SecurityDomain("JBossWS") @RolesAllowed("friend") public class EndpointEJB implements EndpointInterface { ... }
- You can also modify
JBOSS_HOME/server/PROFILE/deploy/jbossws.sar/jboss-management.war/WEB-INF/jboss-web.xml
and specify the security domain.<jboss-web> <security-domain>JBossWS</security-domain> </jboss-web>
Note
For more information about Security Domains, refer to the JBoss Security Guide.Define the security domain for POJO endpoints
Modify theJBOSS_HOME/server/PROFILE/deploy/jbossws.sar/jboss-management.war/WEB-INF/jboss-web.xml
and specify the security domain.<jboss-web> <security-domain>JBossWS</security-domain> </jboss-web>
Define the security context
Configure the security context in theJBOSS_HOME/server/PROFILE/conf/login-config.xml
file.<!-- A template configuration for the JBossWS security domain. This defaults to the UsersRolesLoginModule the same as other and should be changed to a stronger authentication mechanism as required. --> <application-policy name="JBossWS"> <authentication> <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required"> <module-option name="usersProperties">props/jbossws-users.properties</module-option> <module-option name="rolesProperties">props/jbossws-roles.properties</module-option> <module-option name="unauthenticatedIdentity">anonymous</module-option> </login-module> </authentication> </application-policy>
Note
The defaultUsersRolesLoginModule
should be changed to another login module that offers security suitable for your enterprise deployment. Follow Task: Enable LDAP Authentication for steps to use the LdapLoginModule to control user authentication.Define HTTP basic authentication for EJB3 endpoints
Use @WebContext annotation on the bean class.@Stateless @SecurityDomain("JBossWS") @RolesAllowed("friend") @WebContext(contextRoot="/my-cxt", urlPattern="/*", authMethod="BASIC", transportGuarantee="NONE", secureWSDLAccess=false) public class EndpointEJB implements EndpointInterface { ... }
Define HTTP basic authentication for POJO endpoints
Add into WEB-INF/web.xml of your web application<login-config> <auth-method>BASIC</auth-method> <realm-name>Test Realm</realm-name> </login-config>
Client side - set username and password
A web service client can use thejavax.xml.ws.BindingProvider
interface to set the username and password combination.URL wsdlURL = new File("resources/jaxws/samples/context/WEB-INF/wsdl/TestEndpoint.wsdl").toURL(); QName qname = new QName("http://org.jboss.ws/jaxws/context", "TestEndpointService"); Service service = Service.create(wsdlURL, qname); port = (TestEndpoint)service.getPort(TestEndpoint.class); BindingProvider bp = (BindingProvider)port; bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "jsmith"); bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "PaSSw0rd");
Client side - WSDL secured
Use java.net.Authenticator to set username and password when accessing wsdl file.Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username,password.toCharArray()); } }); Service service = Service.create(wsdlURL, qname);
Task: Enable LDAP Authentication
Task Summary
Secure access to the Stateless Session Bean
Secure access to the Stateless Session Bean (SLSB) using the@RolesAllowed
,@PermitAll
,@DenyAll
annotations.The allowed user roles can be set with these annotations both on the bean class and on any of its business methods.@Stateless @RolesAllowed("friend") public class EndpointEJB implements EndpointInterface { ... }
Secure POJO endpoints
Secure Plain Old Java Object (POJO) endpoints by defining a <security-constraint> in theWEB-INF/web.xml
file of the application.The <auth-constraint> <role-name> element specifies whether authentication is mandatory. It can be set to "not required" by specifying an asterisk (*) value in the <role-name> element.<security-constraint> <web-resource-collection> <web-resource-name>All resources</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>*</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>JBossWS</realm-name> </login-config>
Note
For more information about valid <auth-method> values, refer to the Web Content Security Constraints section of the JBoss Security Guide.Define the security domain
Declare the security domain by appending the @SecurityDomain annotation@Stateless @SecurityDomain("JBossWS") @RolesAllowed("friend") public class EndpointEJB implements EndpointInterface { ... }
- You can also modify
JBOSS_HOME/server/PROFILE/deploy/jbossws.sar/jboss-management.war/WEB-INF/jboss-web.xml
and specify the security domain.<jboss-web> <security-domain>JBossWS</security-domain> </jboss-web>
Note
For more information about Security Domains, refer to the JBoss Security Guide.Define the security context
Configure the security context in theJBOSS_HOME/server/PROFILE/conf/login-config.xml
file.<application-policy name="JBossWS"> <authentication> <login-module code="org.jboss.security.auth.spi.LdapLoginModule" flag="required"> <module-option name="java.naming.factory.initial">com.sun.jndi.ldap.LdapCtxFactory</module-option> <module-option name="java.naming.provider.url">ldap://ldaphost.jboss.org:1389/</module-option> <module-option name="java.naming.security.authentication">simple</module-option> <module-option name="principalDNPrefix">uid=</module-option> <module-option name="principalDNSuffix">,ou=People,dc=jboss,dc=org</module-option> <module-option name="rolesCtxDN">ou=Roles,dc=jboss,dc=org</module-option> <module-option name="uidAttributeID">member</module-option> <module-option name="matchOnUserDN">true</module-option> <module-option name="roleAttributeID">cn</module-option> <module-option name="roleAttributeIsDN">false </module-option> </login-module> </authentication> </application-policy>
Note
Refer to the Security Guide for information about the LdapLoginModule and other available login modules.
11.4.1. Java Authentication and Authorization Service
Procedure 11.1. On the Server
Specify Interceptors
Specify (possibly by using ajbossws-cxf.xml
descriptor):- An interceptor for performing authentication and populating a valid
SecurityContext
; the provided interceptor should extendorg.apache.cxf.ws.security.wss4j.AbstractUsernameTokenAuthenticatingInterceptor
.JBossWS integration comes withorg.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingInterceptor
for this use. - An interceptor for performing authorization; CXF requires this to extend
org.apache.cxf.interceptor.security.AbstractAuthorizingInInterceptor
.For instance, theSimpleAuthorizingInterceptor
can be used for mapping endpoint operations to allowed roles.
Example 11.1.
SimpleAuthorizingInterceptor
<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 be delegated to the security domain configured for the endpoint.
Note
Procedure 11.2. On the Client
- Ensure the username is provided through the API (or a custom Spring configuration used to load the Bus):
Example 11.2. Username API
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 are using an older JBossWS-CXF version, or you are not configuring the application server authorization integration, you can use a password callback handler on server side too, configured through aWSS4JInInterceptor
:Example 11.3. Callback Handler
<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>
Example 11.4.
WSS4JInInterceptor
callback handlerpackage 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."); } }
11.5. Further Information
11.5.1. Samples
11.5.2. Username/password configuration
jbossws-cxf.xml
(or programmatically) through the passwordCallbackClass
attribute.
11.5.3. Crypto Algorithms
Chapter 12. SOAP Message Logging
cxf-extension-jbossws.xml
file contains the JBossWS extensions to the Apache CXF stack. You need to manually add this file and link it in the cxf.extensions
file. In cxf-extension-jbossws-xml
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>
cxf-extension-jbossws.xml
contents, you need to re-pack the jar or zip. Alternatively, Apache CXF offers multiple ways of configuring SOAP message logging; for programmatic configuration, the below annotations can be used on either the SEI or the SEI implementation class. If placed on the SEI, they activate logging both for client and server; if on the SEI implementation class, they are relevant just for server-side logging.
@javax.jws.WebService(portName = "MyWebServicePort", serviceName = "MyWebService", ...) @Features(features = "org.apache.cxf.feature.LoggingFeature") public class MyWebServicePortTypeImpl implements MyWebServicePortType {
import org.apache.cxf.interceptor.InInterceptors; import org.apache.cxf.interceptor.OutInterceptors; @javax.jws.WebService(portName = "WebServicePort", serviceName = "WebServiceService", ...) @InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor") @OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor") public class WebServicePortTypeImpl implements WebServicePortType {
import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.LoggingInInterceptor; import org.apache.cxf.interceptor.LoggingOutInterceptor; public class WSClient { public static void main (String[] args) { MyService ws = new MyService(); MyPortType port = ws.getPort(); Client client = ClientProxy.getClient(port); client.getInInterceptors().add(new LoggingInInterceptor()); client.getOutInterceptors().add(new LoggingOutInterceptor()); // make WS calls...
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core" 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"> <cxf:bus> <cxf:features> <cxf:logging/> </cxf:features> </cxf:bus> </beans>
12.1. Debugging Tools
- Tcpmon
- TCPMon allows you to easily view messages as they go back and forth on the wire.
- WSMonitor
- WSMonitor is another option to Tcpmon with slightly more functionality.
- SOAP UI
- SOAP UI can also be used for debugging. In addition to viewing messages, it allows you send messages and load test your services. It also has plug-ins for Eclipse, IDEA and NetBeans.
- Wireshark
- Wireshark, a network packet analyzer, is useful for following the routing of SOAP messages. It can also help when you are getting an HTML error message from the server that your CXF client cannot normally process, by allowing you to see the non-SOAP error message.
Appendix A. Revision History
Revision History | |||
---|---|---|---|
Revision 5.2.0-100.400 | 2013-10-31 | Rüdiger Landmann | |
| |||
Revision 5.2.0-100 | Wed 23 Jan 2013 | Russell Dickenson | |
| |||
Revision 5.1.2-100 | Thu 8 December 2011 | Russell Dickenson | |
|