Web Services Framework for WildFly

Table of Contents

Preface

This book covers the documentation for the current JBossWS release.

1. Web Services Introduction

1.1. What is a web service?

A Web service is a software system designed to support interoperable machine-to-machine interaction over a network. It has an interface described in a machine-processable format (specifically WSDL). Other systems interact with the Web service in a manner prescribed by its description using SOAP messages, typically conveyed using HTTP with an XML serialization in conjunction with other Web-related standards.

From W3C Web Services Architecture [1]

Technical details will be later explained in the documentation. What comes out is that web services provide a standard means of interoperating between different software applications. Each of these applications may run on a variety of platforms and/or frameworks providing a set of functionalities. The main concern is about interoperability between services.

  • A service provider publishes a service contract that exposes the public functions (operations) it provides. A service consumers uses those operations to communicate with the provider.

  • Both service providers and service consumers implement concrete software that sends and receives messages in accordance with the service contract agreed to before the communication.

  • Web services specifications define the rules for publishing a service contract.

  • Web services stacks (like JBossWS ) that conform to the specifications provide a software infrastructure to developers for implementing service providers and consumers. This infrastructure enables developers to focus on developing their own business logic in their preferred way, without dealing with the low-level details of message exchange.

1.1.1. Who needs web services?

Enterprise systems communication may benefit from adoption of WS technologies. The Exposure of well designed contracts allows developers to extract an abstract view of service capabilities. The standardization of software contracts can help improve communication with third-party systems and business-to-business integration. It is easier to expand services for the consumer. No more vendor specific implementation details, home-brew communication protocol or custom per-customer settings.

Enterprise system may benefit from web service technologies also for internal heterogeneous subsystems communication. Departments are free to implement providers and consumers in different software languages. As long as a department adheres to the contract, there should be no need for one department to rewrite whole functionalities when another makes alterations and enhancements to their code.

1.1.2. What web services are not…​

Web services are not the solution for every software system communication.

Web services are meant to be used for loosely-coupled coarse-grained communication and message (document) exchange.

Web service specifications ( WS-* ) have evolved to standardize ws-related advanced aspects including reliable messaging, message-level security, cross-service transactions, etc. Web service specifications also include the notion of registries to collect service contract references and mechanisms to discover service implementations.

1.2. From concepts to technology

1.2.1. Service contracts

Contracts carry technical constraints and requirements of the exposed service as well as information about data to be exchange to interact with the service. They comprise technical descriptions and optional non-technical documents. The latter might include human readable description of the service and the business process it is part of as well as service level agreement / quality of provided service information.

Technical description

Service description is mainly provided using the standard Web Service Description Language (WSDL) . Practically speaking this means one or more XML files contains information including the service location ( endpoint address ), the service functionalities ( operations ), the input/output messages involved in the communication and the business data structure. The latter is basically one or more XML Schema definition . Moreover recent specifications like ( WS-Policy ) allow for advanced service capabilities to be stated in the contract through WSDL extensions.

Web service stacks like JBossWS usually have tools to both generate and consume technical contracts. This helps ensure that owners of service producer ( server ) and consumer ( client ) declare valid contracts to establish the communication.

Contract delivery process

One of the main concerns about service contracts is the way they’re obtained.

Bottom-Up approach

As previously said, tools allow developers to automatically generate WSDL contract files given their service implementation. Advantages and disadvantage of this delivery process include:

  • Developers do not have to deal with contracts by hand thus deep knowledge of WSDL and XML is not required.

  • Less effort and time is required for services to be developed and go live to a production environment.

  • Contracts usually need frequent maintenance, refactoring and versioning.

Down approach

Developers may write contracts first instead. This usually implies an initial collaboration of architects and business analysts to define a conceptual service design together.

  • Services with contracts obtained this way may easily cooperate in a service oriented architecture

  • More effort and time is required for web service project start-up

  • Deep knowledge of WSDL and related technology is required

  • Contracts tend to have longer lifespans and usually require less maintenance.

1.2.2. Message exchange

As stated by the W3C definition , the communication between web services is standardized by the SOAP specification. This means XML messages flow from the provider and consumer endpoints.

Messages' content is described in the wsdl contract. The WSDL file also states the to be used for the transmission. The most common transport protocol is HTTP, however JMS, SMTP and other ones are allowed.

1.2.3. Advanced Web Services technologies

The above specifications are quite common nowadays in the IT industry. Many enterprises have used them for years.

In recent years specifications have been created for security (WS-Security) and reliable messaging (WS-Reliable Messaging). Important functionality in delivering mission critical enterprise services.

2. Quick Start

JBossWS uses WildFly as its target container. The following examples focus on web service features that leverage EJB3 service implementations and the JAX-WS programming models. For further information on POJO service implementations and advanced topics consult the Jakarta XML Web Services User Guide .

2.1. Developing web service implementations

Jakarta XML Web Services leverages annotations in order to express web service meta data on Java components and to describe the mapping between Java data types and XML. When developing web service implementations one needs to decide whether to start with an abstract contract (WSDL) or a Java component.

It is common practice for a developer create the web service in Java and use vendor tools to generate the corresponding WSDL. For this reason we are going to look at a service implementation that leverages Jakarta Web Service Metadata .

Important

Even though detailed knowledge of web service meta data is not required, it will definitely help if you make yourself familiar with it. For further information see

2.1.1. The service implementation class

When starting from Java, a service (endpoint) implementation must be provided. A valid endpoint implementation class must meet the following requirements:

  • It must carry a jakarta.jws.WebService annotation (see Jakarta Web Service Metadata)

  • All method parameters and return types must be compatible with the JAXB 3.0

Let’s look at a sample EJB3 component that exposes as a web service.

For now ignore the EJB3 annotation @Stateless . Focus on the @WebService annotation.

Implementing the service
package org.jboss.test.ws.jaxws.samples.retail.profile;

import jakarta.ejb.Stateless;
import jakarta.jws.WebService;
import jakarta.jws.WebMethod;
import jakarta.jws.soap.SOAPBinding;

@Stateless                                                             (1)
@WebService(                                                           (2)
   name="ProfileMgmt",
   targetNamespace = "http://org.jboss.ws/samples/retail/profile",
   serviceName = "ProfileMgmtService")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)         (3)
public class ProfileMgmtBean {

   @WebMethod                                                          (4)
   public DiscountResponse getCustomerDiscount(DiscountRequest request) {
      return new DiscountResponse(request.getCustomer(), 10.00);
   }
}
1. This endpoint is using a stateless session bean implementation
2. This web service has an explicit namespace, (http://org.jboss.ws/samples/retail/profile)
3. The endpoint is declared to use a doc/lit bare parameter style.  This affects the endpoint statements generated in the WSDL.
4. 'getCustomerDiscount' is the public operation that a consumer can call.
What about the payload?

The method parameters and return values represent the XML payload, because this is a stateless session bean the parameters and return value must be compatible with JAXB3. No JAXB annotations are needed for this example.

package org.jboss.test.ws.jaxws.samples.retail.profile;

import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlType;

import org.jboss.test.ws.jaxws.samples.retail.Customer;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(                                                  (1)
  name = "discountRequest",
  namespace="http://org.jboss.ws/samples/retail/profile",
  propOrder = { "customer" }
)
public class DiscountRequest {

   protected Customer customer;

   public DiscountRequest() {
   }

   public DiscountRequest(Customer customer) {
      this.customer = customer;
   }

   public Customer getCustomer() {
      return customer;
   }

   public void setCustomer(Customer value) {
      this.customer = value;
   }

}
1. @XmlType is used to declare an XML type named, discountRequest, and a namespace name, (http://org.jboss.ws/samples/retail/profile).
Note

For more complex XML mapping consult the JAXB documentation .

2.1.2. Deploying service implementations

Web service deployment depends on the implementation type. Web services can be implemented as plain old Java objects, POJO or as EJB3 components.

EJB3 services

Create a JAR containing the service implementation class, the endpoint interface and any custom data types needed. Drop the JAR in the deployment directory. No additional deployment descriptors required. Any meta data required for the deployment of the actual web service is taken from the annotations provided in the implementation class and the service endpoint interface. JBossWS intercepts the EJB3 deployment (the bean will be there) and creates an HTTP endpoint at deploy-time.

The JAR package structure

jar -tf jaxws-samples-retail.jar

org/jboss/test/ws/jaxws/samples/retail/profile/DiscountRequest.class
org/jboss/test/ws/jaxws/samples/retail/profile/DiscountResponse.class
org/jboss/test/ws/jaxws/samples/retail/profile/ObjectFactory.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmt.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtBean.class
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtService.class
org/jboss/test/ws/jaxws/samples/retail/profile/package-info.class
Important

If the deployment was successful you should be able to see your endpoint in the application server management console.

2.2. Consuming web services

When creating web service clients, one usually starts from the WSDL, but deciphering the WSDL can be complicated. JBossWS ships with a set of tools to generate the required JAX-WS artifacts to build client implementations. The following section looks at a basic usage pattern. For a more detailed introduction to the web service client please consult the user guide.

2.2.1. Creating the client artifacts

Using wsconsume

The wsconsume tool is used to consume the abstract contract (WSDL) and produce annotated Java classes. The following discussion starts with the WSDL from our retail example (ProfileMgmtService.wsdl) above. For a detailed tool reference consult the user guide.

wsconsume is a command line tool that generates
portable JAX-WS artifacts from a WSDL file.

usage: org.jboss.ws.tools.jaxws.command.wsconsume [options] <wsdl-url>

options:
    -h, --help                  Show this help message
    -b, --binding=<file>        One or more JAX-WS or JAXB binding files
    -k, --keep                  Keep/Generate Java source
    -c  --catalog=<file>        Oasis XML Catalog file for entity resolution
    -p  --package=<name>        The target package for generated source
    -w  --wsdlLocation=<loc>    Value to use for @WebService.wsdlLocation
    -o, --output=<directory>    The directory to put generated artifacts
    -s, --source=<directory>    The directory to put Java source
    -q, --quiet                 Be somewhat more quiet
    -t, --show-traces           Show full exception stack traces

Let’s try it on our sample:

~./wsconsume.sh -k -p org.jboss.test.ws.jaxws.samples.retail.profile ProfileMgmtService.wsdl  (1)

org/jboss/test/ws/jaxws/samples/retail/profile/Customer.java
org/jboss/test/ws/jaxws/samples/retail/profile/DiscountRequest.java
org/jboss/test/ws/jaxws/samples/retail/profile/DiscountResponse.java
org/jboss/test/ws/jaxws/samples/retail/profile/ObjectFactory.java
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmt.java
org/jboss/test/ws/jaxws/samples/retail/profile/ProfileMgmtService.java
org/jboss/test/ws/jaxws/samples/retail/profile/package-info.java
  1. Note we used the -p switch to specify the package name of the generated sources.

The generated artifacts explained
File Purpose

ProfileMgmt.java

Service Endpoint Interface

Customer.java

Custom data type

Discount*.java

Custom data type

ObjectFactory.java

JAXB XML Registry

package-info.java

Holder for JAXB package annotations

ProfileMgmtService.java

Service factory

wsconsume generates all the custom data types (JAXB annotated classes), the service endpoint interface and a service factory class.

2.2.2. Constructing a service stub

Web service clients make use of a service stub that hides the details of a remote web service invocation. To a client application a WS invocation looks like an invocation of any other business component. In this case the service endpoint interface is the business interface. JAX-WS does use a service factory class to construct this as particular service stub:

import jakarta.xml.ws.Service;
[...]
Service service = Service.create(                                 (1)
new URL("http://example.org/service?wsdl"),
new QName("MyService")
);
ProfileMgmt profileMgmt = service.getPort(ProfileMgmt.class);     (2)

// do something with the service stub here...                     (3)
  1. Create a service factory using the WSDL location and the service name

  2. Use the tool created service endpoint interface to build the service stub

  3. Use the stub like any other business interface

2.2.3. Resolving dependencies and running the client

To successfully run a WS client application, a classloader needs to be properly setup to include the JBossWS components and its required transitive dependencies. Depending on the environment the client is run in, this might require adding some jars to the classpath, or adding some artifact dependencies to the maven dependency tree. Even for simply developing a client, users might need to resolve proper dependencies (e.g. to setup their IDE).

Below you will find some options for resolving dependencies and running a WS client using the JBossWS libraries:

Maven project

The JBossWS project is composed of multiple Maven artifacts that can be used to declare dependencies in user Maven projects. In particular, the ` org.jboss.ws.cxf:jbossws-cxf-client ` artifact can be used for getting the whole JBossWS client dependency. Users should simply add a dependency to it in their Maven project and make sure JBossWS components (in particular org.jboss.ws.cxf:jbossws-cxf-factories ) come before jars of any other JAX-WS implementation in your classpath.

JBoss Modules environment

One approach for running a WS client is to leverage JBoss Modules, creating a classloading environment equivalent to the server container WS endpoints run in. This is achieved by using the jboss-modules.jar coming with WildFly as follows:

java -jar $WILDFLY_HOME/jboss-modules.jar -mp $WILDFLY_HOME/modules -jar client.jar

The client.jar is meant to contain the WS client application and include a MANIFEST.MF file specifying the proper Main-Class as well as JBoss Modules dependencies, for instance:

Manifest-Version: 1.0
Main-Class: org.jboss.test.ws.jaxws.jbws1666.TestClient
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client
Flat classpath setup

Alternatively, users can setup their application classpath manually (e.g when compiling and running the application directly through javac / java command or using Ant ).

2.3. Maven archetype quick start

A convenient approach to start a new project aiming at providing and/or consuming a JAX-WS endpoint is to use the JBossWS jaxws-codefirst Maven Archetype. A starting project (including working build and sample helloworld client and endpoint) is created in few seconds. It’s simply a matter of issuing a command and answering several simple questions about the desired artifact and group ids for the project being generated:

> mvn archetype:generate -Dfilter=org.jboss.ws.plugins.archetypes:

The generated project includes:

  • a sample HelloWorld code-first POJO endpoint

  • an integration test that gets the WSDL contract for the above service, builds a client and invokes the endpoint

  • a pom.xml for creating a war archive; the project has proper WS component dependencies and uses both wsprovide and wsconsume maven plugins for generating the contract for the code-first endpoint and then generating the client stubs for such contract

  • a plugin for deploying the archive on WildFly.

The project is built and tested by running:

> mvn wildfly:deploy
> mvn integration-test

The build processes the various plugins and calls into the JBossWS tools to generate all the required classes for building the deployment archive and client. The user can test the sample, have a look at the project structure and then either trash the sample endpoint and testcase and replace them with his own components, or modify them step-by-step to achieve their own needs.

2.4. Appendix

2.4.1. Sample wsdl contract

<definitions
    name='ProfileMgmtService'
    targetNamespace='http://org.jboss.ws/samples/retail/profile'
    xmlns='http://schemas.xmlsoap.org/wsdl/'
    xmlns:ns1='http://org.jboss.ws/samples/retail'
    xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/'
    xmlns:tns='http://org.jboss.ws/samples/retail/profile'
    xmlns:xsd='http://www.w3.org/2001/XMLSchema'>

   <types>

      <xs:schema targetNamespace='http://org.jboss.ws/samples/retail'
                 version='1.0' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
         <xs:complexType name='customer'>
            <xs:sequence>
               <xs:element minOccurs='0' name='creditCardDetails' type='xs:string'/>
               <xs:element minOccurs='0' name='firstName' type='xs:string'/>
               <xs:element minOccurs='0' name='lastName' type='xs:string'/>
            </xs:sequence>
         </xs:complexType>
      </xs:schema>

      <xs:schema
          targetNamespace='http://org.jboss.ws/samples/retail/profile'
          version='1.0'
          xmlns:ns1='http://org.jboss.ws/samples/retail'
          xmlns:tns='http://org.jboss.ws/samples/retail/profile'
          xmlns:xs='http://www.w3.org/2001/XMLSchema'>

         <xs:import namespace='http://org.jboss.ws/samples/retail'/>
         <xs:element name='getCustomerDiscount'
                     nillable='true' type='tns:discountRequest'/>
         <xs:element name='getCustomerDiscountResponse'
                     nillable='true' type='tns:discountResponse'/>
         <xs:complexType name='discountRequest'>
            <xs:sequence>
               <xs:element minOccurs='0' name='customer' type='ns1:customer'/>

            </xs:sequence>
         </xs:complexType>
         <xs:complexType name='discountResponse'>
            <xs:sequence>
               <xs:element minOccurs='0' name='customer' type='ns1:customer'/>
               <xs:element name='discount' type='xs:double'/>
            </xs:sequence>
         </xs:complexType>
      </xs:schema>

   </types>

   <message name='ProfileMgmt_getCustomerDiscount'>
      <part element='tns:getCustomerDiscount' name='getCustomerDiscount'/>
   </message>
   <message name='ProfileMgmt_getCustomerDiscountResponse'>
      <part element='tns:getCustomerDiscountResponse'
            name='getCustomerDiscountResponse'/>
   </message>
   <portType name='ProfileMgmt'>
      <operation name='getCustomerDiscount'
                 parameterOrder='getCustomerDiscount'>

         <input message='tns:ProfileMgmt_getCustomerDiscount'/>
         <output message='tns:ProfileMgmt_getCustomerDiscountResponse'/>
      </operation>
   </portType>
   <binding name='ProfileMgmtBinding' type='tns:ProfileMgmt'>
      <soap:binding style='document'
                    transport='http://schemas.xmlsoap.org/soap/http'/>
      <operation name='getCustomerDiscount'>
         <soap:operation soapAction=''/>
         <input>

            <soap:body use='literal'/>
         </input>
         <output>
            <soap:body use='literal'/>
         </output>
      </operation>
   </binding>
   <service name='ProfileMgmtService'>
      <port binding='tns:ProfileMgmtBinding' name='ProfileMgmtPort'>

         <soap:address
             location='http://<HOST>:<PORT>/jaxws-samples-retail/ProfileMgmtBean'/>
      </port>
   </service>
</definitions>

3. Jakarta XML Web Services User Guide

The Jakarta XML Web Services(JAX-WS) defines the mapping between WSDL and Java as well as the classes to be used for accessing webservices and publishing them. JBossWS implements the latest Jakarta XML Web Services specification, hence users can reference it for any vendor agnostic webservice usage. Below is a brief overview of the most basic functionalities.

3.1. Web Service Endpoints

Jakarta XML Web Services simplifies the development model for a web service endpoint. An endpoint implementation bean is annotated with JAX-WS annotations and deployed to the server. The server automatically generates and publishes the abstract contract (i.e. wsdl+schema) for client consumption. All marshalling/unmarshalling is delegated to https://jakarta.ee/specifications/xml-binding[Jakarta XML Binding (JAXB).

3.1.1. Plain old Java Object (POJO)

The following is a simple POJO endpoint implementation. All endpoint associated metadata is provided via Jakarta Web Service Metadata annotations

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class JSEBean01
{
   @WebMethod
   public String echo(String input)
   {
      ...
   }
}
The endpoint as a web application

A JAX-WS java service endpoint (JSE) is deployed as a web application. Here is a sample web.xml descriptor:

<web-app ...>
  <servlet>
    <servlet-name>TestService</servlet-name>
    <servlet-class>org.jboss.test.ws.jaxws.samples.jsr181pojo.JSEBean01</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestService</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
Packaging the endpoint

A JSR-181 java service endpoint (JSE) is packaged as a web application in a war file.

<war warfile="${build.dir}/libs/jbossws-samples-jsr181pojo.war" webxml="${build.resources.dir}/samples/jsr181pojo/WEB-INF/web.xml">
  <classes dir="${build.dir}/classes">
    <include name="org/jboss/test/ws/samples/jsr181pojo/JSEBean01.class"/>
  </classes>
</war>

Note, only the endpoint implementation bean and web.xml are required.

Accessing the generated WSDL

A successfully deployed service endpoint shows up in the WildFly management console. The deployed endpoint wsdl address can be found there.

Important

Note, it is also possible to generate the abstract contract offline using JBossWS tools. For details of that please see Bottom-Up (Java to WSDL).

3.1.2. EJB3 Stateless Session Bean (SLSB)

The JAX-WS programming model supports the same set of annotations on EJB3 stateless session beans as on POJO endpoints.

@Stateless
@Remote(EJB3RemoteInterface.class)
@RemoteBinding(jndiBinding = "/ejb3/EJB3EndpointInterface")

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class EJB3Bean01 implements EJB3RemoteInterface
{
   @WebMethod
   public String echo(String input)
   {
      ...
   }
}

Above you see an EJB-3.0 stateless session bean that exposes one method both on the remote interface and as an endpoint operation.

Packaging the endpoint

A Jakarta Web Service Metadata EJB service endpoint is packaged as an ordinary ejb deployment.

<jar jarfile="${build.dir}/libs/jbossws-samples-jsr181ejb.jar">
  <fileset dir="${build.dir}/classes">
    <include name="org/jboss/test/ws/samples/jsr181ejb/EJB3Bean01.class"/>
    <include name="org/jboss/test/ws/samples/jsr181ejb/EJB3RemoteInterface.class"/>
  </fileset>
</jar>
Accessing the generated WSDL

A successfully deployed service endpoint shows up in the WildFly management console. The deployed endpoint wsdl address can be found there.

Important

Note, it is also possible to generate the abstract contract offline using JBossWS tools. For details of that please see Bottom-Up (Java to WSDL).

3.1.3. Endpoint Provider

JAX-WS services typically implement a native Java service endpoint interface (SEI), perhaps mapped from a WSDL port type, either directly or via the use of annotations.

Java SEIs provide a high level Java-centric abstraction that hides the details of converting between Java objects and their XML representations for use in XML-based messages. However, in some cases it is desirable for services to be able to operate at the XML message level. The Provider interface offers an alternative to SEIs and may be implemented by services wishing to work at the XML message level.

A Provider based service instances invoke method is called for each message received for the service.

@WebServiceProvider(wsdlLocation = "WEB-INF/wsdl/Provider.wsdl")
@ServiceMode(value = Service.Mode.PAYLOAD)
public class ProviderBeanPayload implements Provider<Source>
{
   public Source invoke(Source req)
   {
      // Access the entire request PAYLOAD and return the response PAYLOAD
   }
}

Note, Service.Mode.PAYLOAD is the default and does not have to be declared explicitly. The Service.Mode.MESSAGE can be used to access the entire SOAP message (i.e. with MESSAGE the Provider can also see SOAP Headers)

The abstract contract for a provider endpoint cannot be derived/generated automatically. Therefore, it is necessary to specify the wsdlLocation with the @ WebServiceProvider annotation.

3.2. Web Service Clients

3.2.1. Service

Service is an abstraction that represents a WSDL service. A WSDL service is a collection of related ports, each of which consists of a port type bound to a particular protocol and available at a particular endpoint address.

Most clients are started with a set of stubs generated from the WSDL. One of these will be the service, and you will create objects of that class in order to work with the service (see "static case" below).

Service Usage
Static case

Most clients will start with a WSDL file, and generate some stubs using JBossWS' tool, wsconsume . This usually generates a set of files, one of which is the top of the tree. This is the service implementation class.

The generated implementation class can be recognized as it will have two public constructors, one with no arguments and one with two arguments. The two constructor arguments represent the wsdl location (a java.net.URL ) and the service name (a javax.xml.namespace.QName ) respectively.

Usually the no-argument constructor will be used. In this case the WSDL location and service name are those found in the WSDL. These are set implicitly from the @WebServiceClient annotation that decorates the generated class.

The following code snippet shows the generated constructors from the generated class:

// Generated Service Class

@WebServiceClient(name="StockQuoteService", targetNamespace="http://example.com/stocks", wsdlLocation="http://example.com/stocks.wsdl")
public class StockQuoteService extends jakarta.xml.ws.Service
{
   public StockQuoteService()
   {
      super(new URL("http://example.com/stocks.wsdl"), new QName("http://example.com/stocks", "StockQuoteService"));
   }

   public StockQuoteService(String wsdlLocation, QName serviceName)
   {
      super(wsdlLocation, serviceName);
   }

   ...
}

Section Dynamic Proxy explains how to obtain a port from the service and how to invoke an operation on the port. If you need to work with the XML payload directly or with the XML representation of the entire SOAP message, have a look at Dispatch .

Dynamic case

In the dynamic case, when nothing is generated, a web service client uses Service.create to create Service instances, the following code illustrates this process.

URL wsdlLocation = new URL("http://example.org/my.wsdl");
QName serviceName = new QName("http://example.org/sample", "MyService");
Service service = Service.create(wsdlLocation, serviceName);
Handler Resolver

JAX-WS provides a flexible plug-in framework for message processing modules, known as handlers, that may be used to extend the capabilities of a JAX-WS runtime system. The Handler Framework describes the handler framework in detail. A Service instance provides access to a HandlerResolver via a pair of getHandlerResolver / setHandlerResolver methods that may be used to configure a set of handlers on a per-service, per-port or per-protocol binding basis.

When a Service instance is used to create a proxy or a Dispatch instance then the handler resolver currently registered with the service is used to create the required handler chain. Subsequent changes to the handler resolver configured for a Service instance do not affect the handlers on previously created proxies, or Dispatch instances.

Executor

Service instances can be configured with a java.util.concurrent.Executor . The executor will then be used to invoke any asynchronous callbacks requested by the application. The setExecutor and getExecutor methods of Service can be used to modify and retrieve the executor configured for a service.

3.2.2. Dynamic Proxy

An instance of a client proxy can be created using one of getPort methods on the Service .

/**
 * The getPort method returns a proxy. A service client
 * uses this proxy to invoke operations on the target
 * service endpoint. The <code>serviceEndpointInterface</code>
 * specifies the service endpoint interface that is supported by
 * the created dynamic proxy instance.
 **/
public <T> T getPort(QName portName, Class<T> serviceEndpointInterface)
{
   ...
}

/**
 * The getPort method returns a proxy. The parameter
 * <code>serviceEndpointInterface</code> specifies the service
 * endpoint interface that is supported by the returned proxy.
 * In the implementation of this method, the JAX-WS
 * runtime system takes the responsibility of selecting a protocol
 * binding (and a port) and configuring the proxy accordingly.
 * The returned proxy should not be reconfigured by the client.
 *
 **/
public <T> T getPort(Class<T> serviceEndpointInterface)
{
   ...
}

The service endpoint interface (SEI) is usually generated using tools. For details see Top Down (WSDL to Java)

A generated static Service usually offers typed methods to get ports. These methods also return dynamic proxies that implement the SEI.

@WebServiceClient(name = "TestEndpointService", targetNamespace = "http://org.jboss.ws/wsref",
   wsdlLocation = "http://localhost.localdomain:8080/jaxws-samples-webserviceref?wsdl")

public class TestEndpointService extends Service
{
    ...

    public TestEndpointService(URL wsdlLocation, QName serviceName) {
        super(wsdlLocation, serviceName);
    }

    @WebEndpoint(name = "TestEndpointPort")
    public TestEndpoint getTestEndpointPort()
    {
        return (TestEndpoint)super.getPort(TESTENDPOINTPORT, TestEndpoint.class);
    }
}

3.2.3. WebServiceRef

The @WebServiceRef annotation is used to declare a reference to a Web service. It follows the resource pattern exemplified by the jakarta.annotation.Resource annotation in Jakarta Annotations .

There are two uses to the WebServiceRef annotation:

  1. To define a reference whose type is a generated service class. In this case, the type and value element both refer to the generated service class type. Moreover, if the reference type can be inferred by the field/method declaration the annotation is applied to, the type and value elements MAY have the default value (Object.class, that is). If the type cannot be inferred, then at least the type element MUST be present with a non-default value.

  2. To define a reference whose type is a SEI. In this case, the type element MAY be present with its default value if the type of the reference can be inferred from the annotated field/method declaration, but the value element MUST always be present and refer to a generated service class type (a subtype of jakarta.xml.ws.Service). The wsdlLocation element, if present, overrides theWSDL location information specified in the WebService annotation of the referenced generated service class.

    public class EJB3Client implements EJB3Remote
    {
       @WebServiceRef
       public TestEndpointService service4;
    
       @WebServiceRef
       public TestEndpoint port3;
WebServiceRef customization

A number of overrides and extensions are offered to the WebServiceRef annotation. These include

  • define the port that should be used to resolve a container-managed port

  • define default Stub property settings for Stub objects

  • define the URL of a final WSDL document to be used Example:

  <service-ref>
   <service-ref-name>OrganizationService</service-ref-name>
   <wsdl-override>file:/wsdlRepository/organization-service.wsdl</wsdl-override>
  </service-ref>

  <service-ref>
   <service-ref-name>OrganizationService</service-ref-name>
   <config-name>Secure Client Config</config-name>
   <config-file>META-INF/jbossws-client-config.xml</config-file>
   <handler-chain>META-INF/jbossws-client-handlers.xml</handler-chain>
  </service-ref>
 
  <service-ref>
   <service-ref-name>SecureService</service-ref-name>
   <service-impl-class>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpointService</service-impl-class>
   <service-qname>{http://org.jboss.ws/wsref}SecureEndpointService</service-qname>
    <port-component-ref>
     <service-endpoint-interface>org.jboss.tests.ws.jaxws.webserviceref.SecureEndpoint</service-endpoint-interface>
     <port-qname>{http://org.jboss.ws/wsref}SecureEndpointPort</port-qname>
     <stub-property>
      <prop-name>jakarta.xml.ws.security.auth.username</prop-name>
      <prop-value>kermit</prop-value>
     </stub-property>
     <stub-property>
      <prop-name>jakarta.xml.ws.security.auth.password</prop-name>
      <prop-value>thefrog</prop-value>
     </stub-property>
   </port-component-ref>
  </service-ref>

For details please see service-ref_5_0.dtd .

3.2.4. Dispatch

XML Web Services use XML messages for communication between services and service clients. The higher level JAX-WS APIs are designed to hide the details of converting between Java method invocations and the corresponding XML messages, but in some cases operating at the XML message level is desirable. The Dispatch interface provides support for this mode of interaction.

Dispatch supports two usage modes, identified by the constants jakarta.xml.ws.Service.Mode.MESSAGE and jakarta.xml.ws.Service.Mode.PAYLOAD respectively:

Message In this mode, client applications work directly with protocol-specific message structures. E.g., when used with a SOAP protocol binding, a client application would work directly with a SOAP message.

Message Payload In this mode, client applications work with the payload of messages rather than the messages themselves. E.g., when used with a SOAP protocol binding, a client application would work with the contents of the SOAP Body rather than the SOAP message as a whole.

Dispatch is a low level API that requires clients to construct messages or message payloads as XML and requires an intimate knowledge of the desired message or payload structure. Dispatch is a generic class that supports input and output of messages or message payloads of any type.

Service service = Service.create(wsdlURL, serviceName);
Dispatch dispatch = service.createDispatch(portName, StreamSource.class, Mode.PAYLOAD);

String payload = "<ns1:ping xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
dispatch.invokeOneWay(new StreamSource(new StringReader(payload)));

payload = "<ns1:feedback xmlns:ns1='http://oneway.samples.jaxws.ws.test.jboss.org/'/>";
Source retObj = (Source)dispatch.invoke(new StreamSource(new StringReader(payload)));

3.2.5. Asynchronous Invocations

The BindingProvider interface represents a component that provides a protocol binding for use by clients, it is implemented by proxies and is extended by the Dispatch interface.

BindingProvider instances may provide asynchronous operation capabilities. When used, asynchronous operation invocations are decoupled from the BindingProvider instance at invocation time such that the response context is not updated when the operation completes. Instead a separate response context is made available using the Response interface.

public void testInvokeAsync() throws Exception
{
   URL wsdlURL = new URL("http://" + getServerHost() + ":8080/jaxws-samples-asynchronous?wsdl");
   QName serviceName = new QName(targetNS, "TestEndpointService");
   Service service = Service.create(wsdlURL, serviceName);
   TestEndpoint port = service.getPort(TestEndpoint.class);
   Response response = port.echoAsync("Async");
   // access future
   String retStr = (String) response.get();
   assertEquals("Async", retStr);
}

3.2.6. Oneway Invocations

@Oneway indicates that the given web method has only an input message and no output. Typically, a oneway method returns the thread of control to the calling application prior to executing the actual business method.

@WebService (name="PingEndpoint")
@SOAPBinding(style = SOAPBinding.Style.RPC)
public class PingEndpointImpl
{
   private static String feedback;
  
   @WebMethod
   @Oneway
   publicvoid ping()
   {
      log.info("ping");
      feedback = "ok";
   }
  
   @WebMethod
   public String feedback()
   {
      log.info("feedback");
      return feedback;
   }
}

3.2.7. Timeout Configuration

There are two properties to configure the http connection timeout and client receive time out:

public void testConfigureTimeout() throws Exception
{
   //Set timeout until a connection is established
   ((BindingProvider)port).getRequestContext().put("jakarta.xml.ws.client.connectionTimeout", "6000");

   //Set timeout until the response is received
   ((BindingProvider) port).getRequestContext().put("jakarta.xml.ws.client.receiveTimeout", "1000");

   port.echo("testTimeout");
}

3.2.8. HTTP/2 Support

Starting from JBossWS 7.1.0,the new CXF HTTP client transport has been created to better support HTTP/2. This client which is using java.net.http.HttpClient now seamlessly upgrades to HTTP/2 if supported by the server. Otherwise, it falls back to HTTP/1.1. To enable this new client, you must ensure that the contextual property force.urlconnection.http.conduit is explicitly set to false, either in the System properties or the Bus. Otherwise, the default(old) client which based on java.net.HttpURLConnection/javax.net.ssl.HttpsURLConnection is enabled.

To http version for the new client can be defined with the org.apache.cxf.transport.http.forceVersion property. This property can be set to system or bus property. Below is an example illustrating how to enable this new client and enforce the http version to 1.1:

 BusFactory.getDefaultBus().setProperty("force.urlconnection.http.conduit", false);
 BusFactory.getDefaultBus().setProperty("org.apache.cxf.transport.http.forceVersion", "1.1");
 HelloWorld port = getPort();
 String response = port.echo("hello");

But from our tests, this new http client is a bit slower than the old client. Therefore, it’s only recommended to consider using it when the client performance isn’t critical and HTTP/2 support is required. For more information, please check out [CXF documentation](https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=49941#ClientHTTPTransport(includingSSLsupport)-DefaultClientTransport).

3.3. Common API

This sections describes concepts that apply equally to Web Service Endpoints and Web Service Clients.

3.3.1. Handler Framework

The handler framework is implemented by a JAX-WS protocol binding in both client and server side runtimes. Proxies, and Dispatch instances, known collectively as binding providers, each use protocol bindings to bind their abstract functionality to specific protocols.

Client and server-side handlers are organized into an ordered list known as a handler chain. The handlers within a handler chain are invoked each time a message is sent or received. Inbound messages are processed by handlers prior to binding provider processing. Outbound messages are processed by handlers after any binding provider processing.

Handlers are invoked with a message context that provides methods to access and modify inbound and outbound messages and to manage a set of properties. Message context properties may be used to facilitate communication between individual handlers and between handlers and client and service implementations. Different types of handlers are invoked with different types of message context.

Logical Handler

Handlers that only operate on message context properties and message payloads. Logical handlers are protocol agnostic and are unable to affect protocol specific parts of a message. Logical handlers are handlers that implement jakarta.xml.ws.handler.LogicalHandler .

Protocol Handler

Handlers that operate on message context properties and protocol specific messages. Protocol handlers are specific to a particular protocol and may access and change protocol specific aspects of a message. Protocol handlers are handlers that implement any interface derived from jakarta.xml.ws.handler.Handler except jakarta.xml.ws.handler.LogicalHandler .

Service endpoint handlers

On the service endpoint, handlers are defined using the @HandlerChain annotation.

@WebService
@HandlerChain(file = "jaxws-server-source-handlers.xml")
public class SOAPEndpointSourceImpl
{
   ...
}

The location of the handler chain file supports 2 formats

1. An absolute java.net.URL in externalForm. (ex: http://myhandlers.foo.com/handlerfile1.xml )

2. A relative path from the source file or class file. (ex: bar/handlerfile1.xml)

Service client handlers

On the client side, handler can be configured using the @HandlerChain annotation on the SEI or dynamically using the API.

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = (Endpoint)service.getPort(Endpoint.class);
     
BindingProvider bindingProvider = (BindingProvider)port;
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(new LogHandler());
handlerChain.add(new AuthorizationHandler());
handlerChain.add(new RoutingHandler());
bindingProvider.getBinding().setHandlerChain(handlerChain); // important!

3.3.2. Message Context

MessageContext is the super interface for all JAX-WS message contexts. It extends Map<String,Object> with additional methods and constants to manage a set of properties that enable handlers in a handler chain to share processing related state. For example, a handler may use the put method to insert a property in the message context that one or more other handlers in the handler chain may subsequently obtain via the get method.

Properties are scoped as either APPLICATION or HANDLER. All properties are available to all handlers for an instance of an MEP on a particular endpoint. E.g., if a logical handler puts a property in the message context, that property will also be available to any protocol handlers in the chain during the execution of an MEP instance. APPLICATION scoped properties are also made available to client applications (see section 4.2.1) and service endpoint implementations. The defaultscope for a property is HANDLER.

Logical Message Context

Logical Handlers are passed a message context of type LogicalMessageContext when invoked. LogicalMessageContext extends MessageContext with methods to obtain and modify the message payload, it does not provide access to the protocol specific aspects of amessage. A protocol binding defines what component of a message are available via a logical message context. The SOAP binding defines that a logical handler deployed in a SOAP binding can access the contents of the SOAP body but not the SOAP headers whereas the XML/HTTP binding defines that a logical handler can access the entire XML payload of a message.

SOAP Message Context

SOAP handlers are passed a SOAPMessageContext when invoked. SOAPMessageContext extends MessageContext with methods to obtain and modify the SOAP message payload.

3.3.3. Fault Handling

An implementation may throw a SOAPFaultException

public void throwSoapFaultException()
{
   SOAPFactory factory = SOAPFactory.newInstance();
   SOAPFault fault = factory.createFault("this is a fault string!", new QName("http://foo", "FooCode"));
   fault.setFaultActor("mr.actor");
   fault.addDetail().addChildElement("test");
   thrownew SOAPFaultException(fault);
}

or an application specific user exception

public void throwApplicationException() throws UserException
{
   thrownew UserException("validation", 123, "Some validation error");
}
Important

In case of the latter, JBossWS generates the required fault wrapper beans at runtime if they are not part of the deployment

3.4. WS Annotations

For details, see Jakarta XML Web Services

3.4.1. jakarta.xml.ws.ServiceMode

The ServiceMode annotation is used to specify the mode for a provider class, i.e. whether a provider wants to have access to protocol message payloads (e.g. a SOAP body) or the entire protocol messages (e.g. a SOAP envelope).

3.4.2. jakarta.xml.ws.WebFault

The WebFault annotation is used when mapping WSDL faults to Java exceptions, see section 2.5. It is used to capture the name of the fault element used when marshalling the JAXB type generated from the global element referenced by the WSDL fault message. It can also be used to customize the mapping of service specific exceptions to WSDL faults.

3.4.3. jakarta.xml.ws.RequestWrapper

The RequestWrapper annotation is applied to the methods of an SEI. It is used to capture the JAXB generated request wrapper bean and the element name and namespace for marshalling / unmarshalling the bean. The default value of localName element is the operationName as defined in WebMethod annotation and the default value for the targetNamespace element is the target namespace of the SEI.When starting from Java, this annotation is used to resolve overloading conflicts in document literal mode. Only the className element is required in this case.

3.4.4. jakarta.xml.ws.ResponseWrapper

The ResponseWrapper annotation is applied to the methods of an SEI. It is used to capture the JAXB generated response wrapper bean and the element name and namespace for marshalling / unmarshalling the bean. The default value of the localName element is the operationName as defined in the WebMethod appended with ”Response” and the default value of the targetNamespace element is the target namespace of the SEI. When starting from Java, this annotation is used to resolve overloading conflicts in document literal mode. Only the className element is required in this case.

3.4.5. jakarta.xml.ws.WebServiceClient

The WebServiceClient annotation is specified on a generated service class (see 2.7). It is used to associate a class with a specific Web service, identify by a URL to a WSDL document and the qualified name of a wsdl:service element.

3.4.6. jakarta.xml.ws.WebEndpoint

The WebEndpoint annotation is specified on the getPortName() methods of a generated service class (see 2.7). It is used to associate a get method with a specific wsdl:port, identified by its local name (a NCName).

3.4.7. jakarta.xml.ws.WebServiceProvider

The WebServiceProvider annotation is specified on classes that implement a strongly typed jakarta.xml.ws.Provider . It is used to declare that a class that satisfies the requirements for a provider (see 5.1) does indeed define a Web service endpoint, much like the WebService annotation does for SEI-based endpoints.

The WebServiceProvider and WebService annotations are mutually exclusive.

3.4.8. jakarta.xml.ws.BindingType

The BindingType annotation is applied to an endpoint implementation class. It specifies the binding to use when publishing an endpoint of this type.

The default binding for an endpoint is the SOAP 1.1/HTTP one.

3.4.9. jakarta.xml.ws.WebServiceRef

The WebServiceRef annotation is used to declare a reference to a Web service. It follows the resource pattern exemplified by the jakarta.annotation.Resource annotation in Jakarta Annotations [32]. The WebServiceRef annotation is required to be honored when running on the JakartaEE platform, where it is subject to the common resource injection rules described by the platform specification [33].

3.4.10. jakarta.xml.ws.WebServiceRefs

The WebServiceRefs annotation is used to declare multiple references to Web services on a single class. It is necessary to work around the limitation against specifying repeated annotations of the same type on any given class, which prevents listing multiple javax.ws.WebServiceRef annotations one after the other. This annotation follows the resource pattern exemplified by the javax.annotation.Resources annotation in JSR-250.

Since no name and type can be inferred in this case, each WebServiceRef annotation inside a WebServiceRefs MUST contain name and type elements with non-default values. The WebServiceRef annotation is required to be honored when running on the Java EE 5 platform, where it is subject to the common resource injection rules described by the platform specification.

3.4.11. jakarta.xml.ws.Action

The Action annotation is applied to the methods of a SEI. It used to generate the wsa:Action on wsdl:input and wsdl:output of each wsdl:operation mapped from the annotated methods.

3.4.12. jakarta.xml.ws.FaultAction

The FaultAction annotation is used within the Action annotation to generate the wsa:Action element on the wsdl:fault element of each wsdl:operation mapped from the annotated methods.

3.5. Jakarta Web Service Metadata Annotations

Jakarta Web Service Metadata defines the syntax and semantics of JAX-WS metadata and default values.

For details, see Jakarta Web Service Metadata .

3.5.1. jakarta.jws.WebService

Marks a Java class as implementing a Web Service, or a Java interface as defining a Web Service interface.

3.5.2. jakarta.jws.WebMethod

Customizes a method that is exposed as a Web Service operation.

3.5.3. jakarta.jws.OneWay

Indicates that the given web method has only an input message and no output. Typically, a oneway method returns the thread of control to the calling application prior to executing the actual business method. A JSR-181 processor is REQUIRED to report an error if an operation marked @Oneway has a return value, declares any checked exceptions or has any INOUT or OUT parameters.

3.5.4. jakarta.jws.WebParam

Customizes the mapping of an individual parameter to a Web Service message part and XML element.

3.5.5. jakarta.jws.WebResult

Customizes the mapping of the return value to a WSDL part and XML element.

3.5.6. jakarta.jws.SOAPBinding

Specifies the mapping of the Web Service onto the SOAP message protocol.

The SOAPBinding annotation has a target of TYPE and METHOD . The annotation may be placed on a method if and only if the SOAPBinding.style is DOCUMENT . Implementations MUST report an error if the SOAPBinding annotation is placed on a method with a SOAPBinding.style of RPC . Methods that do not have a SOAPBinding annotation accept the SOAPBinding behavior defined on the type.

3.5.7. jakarta.jws.HandlerChain

The @HandlerChain annotation associates the Web Service with an externally defined handler chain.

It is an error to combine this annotation with the @SOAPMessageHandlers annotation.

The @HandlerChain annotation MAY be present on the endpoint interface and service implementation bean. The service implementation bean’s @HandlerChain is used if @HandlerChain is present on both.

The @HandlerChain annotation MAY be specified on the type only. The annotation target includes METHOD and FIELD for use by JAX-WS-2.x.

4. JAX-WS Tools

The JAX-WS tools provided by JBossWS can be used in a variety of ways. First we will look at server-side development strategies, and then proceed to the client.

4.1. Server side

When developing a Web Service Endpoint (the server-side) you have the option of starting from Java ( bottom-up development ), or from the abstact contract (WSDL) that defines your service ( top-down development ). If this is a new service (no existing contract), the bottom-up approach is the fastest route; you only need to add a few annotations to your classes to get a service up and running. However, if developing a service with an already defined contract, it is far simpler to use the top-down approach, since the provided tool will generate the annotated code for you.

Bottom-up use cases:

  • Exposing an already existing EJB3 bean as a Web Service

  • Providing a new service, and wanting the contract to be generated for you

Top-down use cases:

  • Replacing the implementation of an existing Web Service, and you can’t break compatibility with older clients

  • Exposing a service that conforms to a contract specified by a third party (e.g. a vendor that calls back using an already defined protocol).

  • Creating a service that adheres to the XML Schema and WSDL you developed by hand up front

The following JAX-WS command line tools are included in JBossWS:

Command Description

wsprovide

Generates JAX-WS portable artifacts, and provides the abstract contract. Used for bottom-up development.

wsconsume

Consumes the abstract contract (WSDL and Schema files), and produces artifacts for both a server and client. Used for top-down and client development

4.1.1. Bottom-Up (Using wsprovide)

The bottom-up strategy involves developing the Java code for your service, and then annotating it using JAX-WS annotations. These annotations can be used to customize the contract that is generated for the service. For example, you can change the operation name to map to anything you like. However, all of the annotations have sensible defaults, so only the @WebService annotation is required.

This can be as simple as creating a single class:

package echo;

@jakarta.jws.WebService
public class Echo
{
   public String echo(String input)
   {
      return input;
   }
}

A JSE or EJB3 deployment can be built using this class, and it is the only Java code needed to deploy on JBossWS. The WSDL, and all other Java artifacts called "wrapper classes" will be generated at deploy time. This actually goes beyond the JAX-WS specification, which requires that wrapper classes be generated using an offline tool. The reason for this requirement is purely a vendor implementation problem, and since we do not believe in burdening a developer with a bunch of additional steps, we generate these as well. However, if you want your deployment to be portable to other application servers, you will need to use a tool and add the generated classes to your deployment.

This is the primary purpose of the wsprovide tool, to generate portable JAX-WS artifacts. Additionally, it can be used to "provide" the abstract contract (WSDL file) for your service. This can be obtained by invoking wsprovide using the "-w" option:

$ javac -d . Echo.java
$ wsprovide -w echo.Echo
Generating WSDL:
EchoService.wsdl
Writing Classes:
echo/jaxws/Echo.class
echo/jaxws/EchoResponse.class

Inspecting the WSDL reveals a service called EchoService :

<service name='EchoService'>
 <port binding='tns:EchoBinding' name='EchoPort'>
  <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
 </port>
</service>

As expected, this service defines one operation, " echo ":

<portType name='Echo'>
 <operation name='echo' parameterOrder='echo'>
  <input message='tns:Echo_echo'/>
  <output message='tns:Echo_echoResponse'/>
 </operation>
</portType>
Note

Remember that when deploying on JBossWS you do not need to run this tool. It is only needed for generating portable artifacts and/or the abstract contract for the service.

Let’s create a POJO endpoint for deployment on WildFly. A simple web.xml needs to be created:

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0">

  <servlet>
    <servlet-name>Echo</servlet-name>
    <servlet-class>echo.Echo</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Echo</servlet-name>
    <url-pattern>/Echo</url-pattern>
  </servlet-mapping>
</web-app>

The web.xml and the single class can now be used to create a war:

$ mkdir -p WEB-INF/classes
$ cp -rp echo WEB-INF/classes/
$ cp web.xml WEB-INF
$ jar cvf echo.war WEB-INF
added manifest
adding: WEB-INF/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/(in = 0) (out= 0)(stored 0%)
adding: WEB-INF/classes/echo/Echo.class(in = 340) (out= 247)(deflated 27%)
adding: WEB-INF/web.xml(in = 576) (out= 271)(deflated 52%)

The war can then be deployed to the JBoss Application Server; this will internally invoke wsprovide, which will generate the WSDL. If deployment was successful, and you are using the default settings, it should be available in the server management console.

For a portable JAX-WS deployment, the wrapper classes generated earlier could be added to the deployment.

4.1.2. Down (Using wsconsume)

The top-down development strategy begins with the abstract contract for the service, which includes the WSDL file and zero or more schema files. The wsconsume tool is then used to consume this contract, and produce annotated Java classes (and optionally sources) that define it.

Note

wsconsume may have problems with symlinks on Unix systems

Using the WSDL file from the bottom-up example, a new Java implementation that adheres to this service can be generated. The "-k" option is passed to wsconsume to preserve the Java source files that are generated, instead of providing just classes:

$ wsconsume -k EchoService.wsdl
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java

The following table shows the purpose of each generated file:

File Purpose

Echo.java

Service Endpoint Interface

Echo_Type.java

Wrapper bean for request message

EchoResponse.java

Wrapper bean for response message

ObjectFactory.java

JAXB XML Registry

package-info.java

Holder for JAXB package annotations

EchoService.java

Used only by JAX-WS clients

Examining the Service Endpoint Interface reveals annotations that are more explicit than in the class written by hand in the bottom-up example, however, these evaluate to the same contract:

@WebService(name = "Echo", targetNamespace = "http://echo/")
public interface Echo {
    @WebMethod
    @WebResult(targetNamespace = "")
    @RequestWrapper(localName = "echo", targetNamespace = "http://echo/", className = "echo.Echo_Type")
    @ResponseWrapper(localName = "echoResponse", targetNamespace = "http://echo/", className = "echo.EchoResponse")
    public String echo(
        @WebParam(name = "arg0", targetNamespace = "")
        String arg0);

}

The only missing piece (for packaging) is the implementation class, which can now be written, using the above interface.

package echo;

@jakarta.jws.WebService(endpointInterface="echo.Echo")
public class EchoImpl implements Echo
{
   public String echo(String arg0)
   {
      return arg0;
   }
}

4.2. Client Side

Before going into detail on the client-side it is important to understand the decoupling concept that is central to Web Services. Web Services are not the best fit for internal RPC, even though they can be used in this way. There are much better technologies for this (CORBA, and RMI for example). Web Services was designed specifically for interoperable coarse-grained correspondence. There is no expectation or guarantee that any party participating in a Web Service interaction will be at any particular location, running on any particular OS, or written in any particular programming language, because of this, it is important to clearly separate client and server implementations. The only thing they should have in common is the abstract contract definition. If, for whatever reason, your software does not adhere to this principal, then you should not be using Web Services. For the above reasons, the recommended methodology for developing a client is to follow the top-down approach , even if the client is running on the same server.

Let’s repeat the process of the top-down section, although using the deployed WSDL, instead of the one generated offline by wsprovide . The reason we do this is to get the right value for soap:address. This value must be computed at deploy time, since it is based on container configuration specifics. You could of course edit the WSDL file yourself, although you need to ensure that the path is correct.

Offline version:

<service name='EchoService'>
  <port binding='tns:EchoBinding' name='EchoPort'>
   <soap:address location='REPLACE_WITH_ACTUAL_URL'/>
  </port>
</service>

Online version:

<service name="EchoService">
  <port binding="tns:EchoBinding" name="EchoPort">
    <soap:address location="http://localhost.localdomain:8080/echo/Echo"/>
  </port>
</service>

Using the online deployed version with wsconsume :

$ wsconsume -k http://localhost:8080/echo/Echo?wsdl
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java
echo/Echo.java
echo/EchoResponse.java
echo/EchoService.java
echo/Echo_Type.java
echo/ObjectFactory.java
echo/package-info.java

The one class that was not examined in the top-down section, was EchoService.java . Notice how it stores the location the WSDL was obtained from.

@WebServiceClient(name = "EchoService", targetNamespace = "http://echo/", wsdlLocation = "http://localhost:8080/echo/Echo?wsdl")
public class EchoService extends Service
{
    private final static URL ECHOSERVICE_WSDL_LOCATION;

    static {
        URL url = null;
        try
        {
           url = new URL("http://localhost:8080/echo/Echo?wsdl");
        }
        catch (MalformedURLException e)
        {
           e.printStackTrace();
        }
        ECHOSERVICE_WSDL_LOCATION = url;
    }

    public EchoService(URL wsdlLocation, QName serviceName)
    {
         super(wsdlLocation, serviceName);
    }

    public EchoService()
    {
         super(ECHOSERVICE_WSDL_LOCATION, new QName("http://echo/", "EchoService"));
    }

    @WebEndpoint(name = "EchoPort")
    public Echo getEchoPort()
    {
         return (Echo)super.getPort(new QName("http://echo/", "EchoPort"), Echo.class);
    }
}

This generated class extends the main client entry point in JAX-WS, jakarta.xml.ws.Service . While Service can be used directly, this is far simpler since it provides the configuration info for you. The only method we really care about is the getEchoPort() method, which returns an instance of the Service Endpoint Interface. Any WS operation can then be called by just invoking a method on the returned interface.

Note

It’s not recommended to refer to a remote WSDL URL in a production application. This causes network I/O every time you instantiate the Service Object. Instead, use the tool on a saved local copy, or use the URL version of the constructor to provide a new WSDL location.

All that is left to do, is write and compile the client:

import echo.*;

public class EchoClient
{
   public static void main(String args[])
   {
      if (args.length != 1)
      {
          System.err.println("usage: EchoClient <message>");
          System.exit(1);
      }

      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();
      System.out.println("Server said: " + echo.echo(args[0]));
   }
}

It is easy to change the endpoint address of your operation at runtime, setting the ENDPOINT_ADDRESS_PROPERTY as shown below:

      EchoService service = new EchoService();
      Echo echo = service.getEchoPort();

      /* Set NEW Endpoint Location */
      String endpointURL = "http://NEW_ENDPOINT_URL";
      BindingProvider bp = (BindingProvider)echo;
      bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointURL);

      System.out.println("Server said: " + echo.echo(args[0]));

4.3. WS binding customization

An introduction to binding customizations:

The schema for the binding customization files can be found here:

4.4. wsconsume

wsconsume is a command line tool and ant task that "consumes" the abstract contract (WSDL file) and produces portable JAX-WS service and client artifacts.

4.4.1. Command Line Tool

The command line tool has the following usage:

usage: wsconsume [options] <wsdl-url>
options:
  -h, --help                  Show this help message
  -b, --binding=<file>        One or more JAX-WS or JAXB binding files
  -k, --keep                  Keep/Generate Java source
  -c  --catalog=<file>        Oasis XML Catalog file for entity resolution
  -j  --clientjar=<name>      Create a jar file of the generated artifacts for calling the webservice
  -p  --package=<name>        The target package for generated source
  -w  --wsdlLocation=<loc>    Value to use for @WebServiceClient.wsdlLocation
  -o, --output=<directory>    The directory to put generated artifacts
  -s, --source=<directory>    The directory to put Java source
  -q, --quiet                 Be somewhat more quiet
  -v, --verbose               Show full exception stack traces
  -l, --load-consumer         Load the consumer and exit (debug utility)
  -e, --extension             Enable SOAP 1.2 binding extension
  -a, --additionalHeaders     Enables processing of implicit SOAP headers
  -d, --encoding=<charset>    The charset encoding to use for generated sources
  -n, --nocompile             Do not compile generated sources
Important

The wsdlLocation is used when creating the Service to be used by clients and will be added to the @WebServiceClient annotation, for an endpoint implementation based on the generated service endpoint interface you will need to manually add the wsdlLocation to the @WebService annotation on your web service implementation and not the service endpoint interface.

Examples

Generate artifacts in Java class form only:

wsconsume Example.wsdl

Generate source and class files:

wsconsume -k Example.wsdl

Generate source and class files in a custom directory:

wsconsume -k -o custom Example.wsdl

Generate source and class files in the org.foo package:

wsconsume -k -p org.foo Example.wsdl

Generate source and class files using multiple binding files:

wsconsume -k -b wsdl-binding.xml -b schema1-binding.xml -b schema2-binding.xml

4.4.2. Maven Plugin

The wsconsume tools is included in the org.jboss.ws.plugins:jaxws-tools- maven- plugin plugin. The plugin has two goals for running the tool, wsconsume and wsconsume-test , which basically do the same during different maven build phases (the former triggers the source generation during generate-sources phase, the latter during the generate-test-sources one).

The wsconsume plugin has the following parameters:

Attribute Description Default

bindingFiles

JAXWS or JAXB binding file

true

classpathElements

Each classpathElement provides a library file to be added to classpath

$\{project.compileClasspathElements} or $\{project.testClasspathElements}

catalog

Oasis XML Catalog file for entity resolution

none

targetPackage

The target Java package for generated code.

generated

bindingFiles

One or more JAX-WS or JAXB binding file

none

wsdlLocation

Value to use for @WebServiceClient.wsdlLocation

generated

outputDirectory

The output directory for generated artifacts.

$\{project.build.outputDirectory} or $\{project.build.testOutputDirectory}

sourceDirectory

The output directory for Java source.

$\{project.build.directory}/generated-sources/wsconsume

verbose

Enables more informational output about command progress.

false

wsdls

The WSDL files or URLs to consume

n/a

extension

Enable SOAP 1.2 binding extension.

false

encoding

The charset encoding to use for generated sources.

$\{project.build.sourceEncoding}

argLine

An optional additional argline to be used when running in fork mode; can be used to set endorse dir, enable debugging, etc. Example <argLine>-Djava.endorsed.dirs=…​</argLine>

none

fork

Whether or not to run the generation task in a separate VM.

false

Examples

wsconsume can be used in your own project build by simply referencing the jaxws-tools- maven- plugin in the configured plugins in the projects pom.xml file.

The following example makes the plugin consume the test.wsdl file and generate SEI and wrappers' java sources. The generated sources are then compiled together with the other project classes.

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Final</version>
      <configuration>
        <wsdls>
          <wsdl>${basedir}/test.wsdl</wsdl>
        </wsdls>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

You can also specify multiple wsdl files, as well as force the target package, enable SOAP 1.2 binding and turn the tool’s verbose mode on:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Final</version>
      <configuration>
       <wsdls>
        <wsdl>${basedir}/test.wsdl</wsdl>
        <wsdl>${basedir}/test2.wsdl</wsdl>
       </wsdls>
       <targetPackage>foo.bar</targetPackage>
       <extension>true</extension>
       <verbose>true</verbose>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

If the wsconsume invocation is required for consuming a wsdl to be used in the testsuite only, you might want to use the wsconsume-test goal as follows:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Final</version>
      <configuration>
        <wsdls>
          <wsdl>${basedir}/test.wsdl</wsdl>
        </wsdls>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsconsume-test</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
Plugin stack dependency

The plugin itself does not have an explicit dependency on a JBossWS stack, as it’s meant for use with implementations of any supported version of the JBossWS SPI . The user is expected to set a dependency in his own pom.xml to the desired JBossWS stack version. The plugin will rely on that in using the proper tooling.

<dependencies>
  <dependency>
    <groupId>org.jboss.ws.cxf</groupId>
    <artifactId>jbossws-cxf-client</artifactId>
    <version>5.1.0.Final</version>
  </dependency>
</dependencies>
Tip

Be careful when using this plugin with the Maven War Plugin as that includes project dependencies into the generated application war archive. To avoid that situation set <scope>provided</scope> for the JBossWS stack dependency.

Important

Up to version 1.1.2.Final, the artifactId of the plugin was maven-jaxws-tools-plugin .

4.4.3. Ant Task

The wsconsume Ant task ( org.jboss.ws.tools.ant.WSConsumeTask ) has the following attributes:

Attribute Description Default

fork

Whether or not to run the generation task in a separate VM.

true

keep

Keep/Enable Java source code generation.

false

catalog

Oasis XML Catalog file for entity resolution

none

package

The target Java package for generated code.

generated

binding

A JAX-WS or JAXB binding file

none

wsdlLocation

Value to use for @WebServiceClient.wsdlLocation

generated

encoding

The charset encoding to use for generated sources

n/a

destdir

The output directory for generated artifacts.

"output"

sourcedestdir

The output directory for Java source.

value of destdir

verbose

Enables more informational output about command progress.

false

wsdl

The WSDL file or URL

n/a

extension

Enable SOAP 1.2 binding extension.

false

additionalHeaders

Enables processing of implicit SOAP headers

false

Note

Users also need to put streamBuffer.jar and stax-ex.jar in the classpath of the ant task to generate the appropriate artefacts.

Note

The wsdlLocation is used when creating the Service to be used by clients and will be added to the @WebServiceClient annotation. For an endpoint implementation based on the generated service endpoint interface, you will need to manually add the wsdlLocation to the @WebService annotation on your web service implementation and not the service endpoint interface.

Also, the following nested elements are supported:

Element Description Default

binding

A JAXWS or JAXB binding file

none

jvmarg

Allows setting of custom jvm arguments

 

Examples

The following command generates JAX-WS sources and classes in a separate JVM with separate directories, a custom wsdl location attribute, and a list of binding files from foo.wsdl:

<wsconsume
  fork="true"
  verbose="true"
  destdir="output"
  sourcedestdir="gen-src"
  keep="true"
  wsdllocation="handEdited.wsdl"
  wsdl="foo.wsdl">
  <binding dir="binding-files" includes="*.xml" excludes="bad.xml"/>
</wsconsume>

4.5. wsprovide

wsprovide is a command line tool, Maven plugin and Ant task that generates portable JAX-WS artifacts for a service endpoint implementation. It also has the option to "provide" the abstract contract for offline usage.

4.5.1. Command Line Tool

The command line tool has the following usage:

usage: wsprovide [options] <endpoint class name>
options:
  -h, --help                  Show this help message
  -k, --keep                  Keep/Generate Java source
  -w, --wsdl                  Enable WSDL file generation
  -a, --address               The generated port soap:address in wsdl
  -c. --classpath=<path>      The classpath that contains the endpoint
  -o, --output=<directory>    The directory to put generated artifacts
  -r, --resource=<directory>  The directory to put resource artifacts
  -s, --source=<directory>    The directory to put Java source
  -e, --extension             Enable SOAP 1.2 binding extension
  -q, --quiet                 Be somewhat more quiet
  -t, --show-traces           Show full exception stack traces
Examples

Generates wrapper classes for portable artifacts in the "generated" directory:

wsprovide -o generated foo.Endpoint

Generates wrapper classes and WSDL in the "generated" directory

wsprovide -o generated -w foo.Endpoint

Using an endpoint that references other jars

wsprovide -o generated -c application1.jar:application2.jar foo.Endpoint

4.5.2. Maven Plugin

The wsprovide tools is included in the org.jboss.ws.plugins:jaxws-tools- maven- plugin plugin. The plugin has two goals for running the tool, wsprovide and wsprovide-test , which basically do the same during different Maven build phases (the former triggers the sources generation during process-classes phase, the latter during the process-test-classes one).

The wsprovide plugin has the following parameters:

Attribute Description Default

testClasspathElements

Each classpathElement provides a library file to be added to classpath

$\{project.compileClasspathElements} or $\{project.testClasspathElements}

outputDirectory

The output directory for generated artifacts.

$\{project.build.outputDirectory} or $\{project.build.testOutputDirectory}

resourceDirectory

The output directory for resource artifacts (WSDL/XSD).

$\{project.build.directory}/wsprovide/resources

sourceDirectory

The output directory for Java source.

$\{project.build.directory}/wsprovide/java

extension

Enable SOAP 1.2 binding extension.

false

generateWsdl

Whether or not to generate WSDL.

false

verbose

Enables more informational output about command progress.

false

portSoapAddress

The generated port soap:address in the WSDL

 

endpointClass

Service Endpoint Implementation.

 

Examples

wsprovide can be used in your own project build by simply referencing the jaxws-tools- maven- plugin in the configured plugins in the pom.xml file.

The following example makes the plugin provide the wsdl file and artifact sources for the specified endpoint class:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Final</version>
      <configuration>
        <verbose>true</verbose>
        <endpointClass>org.jboss.test.ws.plugins.tools.wsprovide.TestEndpoint</endpointClass>
        <generateWsdl>true</generateWsdl>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsprovide</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

The following example does the same, but is meant for use in your own testsuite:

<build>
  <plugins>
    <plugin>
      <groupId>org.jboss.ws.plugins</groupId>
      <artifactId>jaxws-tools-maven-plugin</artifactId>
      <version>1.2.0.Final</version>
      <configuration>
        <verbose>true</verbose>
        <endpointClass>org.jboss.test.ws.plugins.tools.wsprovide.TestEndpoint2</endpointClass>
        <generateWsdl>true</generateWsdl>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>wsprovide-test</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
Plugin stack dependency

The plugin itself does not have an explicit dependency on a JBossWS stack, as it’s meant for uses with implementations of any supported version of the JBossWS SPI . The user is expected to set a dependency in his own pom.xml to the desired JBossWS stack version. The plugin will rely on the that for using the proper tooling.

<dependencies>
  <dependency>
    <groupId>org.jboss.ws.cxf</groupId>
    <artifactId>jbossws-cxf-client</artifactId>
    <version>5.1.0.Final</version>
  </dependency>
</dependencies>
Tip

Be careful when using this plugin with the Maven War Plugin as that includes project dependencies in the generated application war archive. Set <scope>provided</scope> on the JBossWS stack dependency to avoid that.

Important

Up to version 1.1.2.Final, the artifactId of the plugin was maven-jaxws-tools-plugin .

4.5.3. Ant Task

The wsprovide ant task ( org.jboss.ws.tools.ant.WSProvideTask ) has the following attributes:

Attribute Description Default

fork

Whether or not to run the generation task in a separate VM.

true

keep

Keep/Enable Java source code generation.

false

destdir

The output directory for generated artifacts.

"output"

resourcedestdir

The output directory for resource artifacts (WSDL/XSD).

value of destdir

sourcedestdir

The output directory for Java source.

value of destdir

extension

Enable SOAP 1.2 binding extension.

false

genwsdl

Whether or not to generate WSDL.

false

address

The generated port soap:address in wsdl.

 

verbose

Enables more informational output about command progress.

false

sei

Service Endpoint Implementation.

 

classpath

The classpath that contains the service endpoint implementation.

"."

Examples

The following command executes wsprovide in verbose mode with separate output directories for source, resources, and classes:

<target name="test-wsproivde" depends="init">
  <taskdef name="wsprovide" classname="org.jboss.ws.tools.ant.WSProvideTask">
    <classpath refid="core.classpath"/>
  </taskdef>
  <wsprovide
    fork="false"
    keep="true"
    destdir="out"
    resourcedestdir="out-resource"
    sourcedestdir="out-source"
    genwsdl="true"
    verbose="true"
    sei="org.jboss.test.ws.jaxws.jsr181.soapbinding.DocWrappedServiceImpl">
    <classpath>
      <pathelement path="${tests.output.dir}/classes"/>
    </classpath>
  </wsprovide>
</target>

5. Advanced User Guide

5.1. Logging

Logging of inbound and outbound messages is a common need. Different approaches are available for achieving that:

5.1.1. JAX-WS Handler approach

A portable way of performing logging is writing a simple JAX-WS handler dumping the messages that are passed to it; the handler can be added to the desired client/endpoints (programmatically / using @HandlerChain JAX-WS annotation).

The Predefined client and endpoint configurations mechanism allows user to add the logging handler to any client/endpoint or to some of them only (in which case the @EndpointConfig annotation / JBossWS API is required though).

5.1.2. Apache CXF approach

Apache CXF also comes with logging interceptors that can be easily used to log messages to the console or configured client/server log files. Those interceptors can be added to client, endpoint and buses in multiple ways:

System property

Setting the org.apache.cxf.logging.enabled system property to true causes the logging interceptors to be added to any Bus instance being created on the JVM.

Important

On WildFly, the system property is set by adding what follows to the standalone / domain server configuration just after the extensions section:

<system-properties>
  <property name="org.apache.cxf.logging.enabled" value="true"/>
</system-properties>
Manual interceptor addition and logging feature

Logging interceptors can be selectively added to endpoints using the Apache CXF annotations @org.apache.cxf.interceptor.InInterceptors and @org.apache.cxf.interceptor.OutInterceptors . The same is achieved on the client side by programmatically adding new instances of the logging interceptors to the client or the bus.

Apache CXF 3.2 has designated @org.apache.cxf.feature.Features the preferred annotation for adding logging capabilities to clients and endpoints. Annotation @org.apache.cxf.annotations.Logging and class org.apache.cxf.feature.LoggingFeature have been deprecated.

Also in Apache CXF 3.2 classes LoggingInInterceptor, LoggingOutInterceptor, and AbstractLoggingInterceptor have been assigned a new package name. The classes in package org.apache.cxf.interceptor have been deprecated. These classes can now be found in package org.apache.cxf.ext.logging.

Please refer to the Apache CXF documentation for more details.

5.2. WS-* support

JBossWS includes most of the WS-* specification functionalities through the integration with Apache CXF. In particular, the whole WS-Security Policy framework is fully supported, enabling full contract driven configuration of complex features like WS-Security.

More information can be found later in this chapter.

5.3. Address rewrite

JBossWS allows users to configure the soap:address attribute in the wsdl contract of deployed services.

5.3.1. Server configuration options

The configuration options are part of the webservices subsystem section of the WildFly domain model.

<subsystem xmlns="urn:jboss:domain:webservices:1.1">
  <wsdl-host>localhost</wsdl-host>
  <modify-wsdl-address>true</modify-wsdl-address>
<!--
  <wsdl-port>8080</wsdl-port>
  <wsdl-secure-port>8443</wsdl-secure-port>
-->
</subsystem>

If the content of <soap:address> in the wsdl is a valid URL, JBossWS will not rewrite it unless modify-wsdl-address is true. If the content of <soap:address> is not a valid URL instead, JBossWS will always rewrite it using the attribute values given below. Please note that the variable $\{jboss.bind.address} can be used to set the address which the application is bound to at each startup.

The wsdl-secure-port and wsdl-port attributes are used to explicitly define the ports to be used for rewriting the SOAP address. If these attributes are not set, the ports will be identified by querying the list of installed connectors. If multiple connectors are found the port of the first connector is used.

5.3.2. Dynamic rewrite

When the application server is bound to multiple addresses or non-trivial real-world network architectures cause request for different external addresses to hit the same endpoint, a static rewrite of the soap:address may not be enough. JBossWS allows for both the soap:address in the wsdl and the wsdl address in the console to be rewritten with the host use in the client request. This way, users always get the right wsdl address assuming they’re connecting to an instance having the endpoint they’re looking for. To trigger this behaviour, the jbossws.undefined.host value has to be specified for the wsdl-host element.

<wsdl-host>jbossws.undefined.host</wsdl-host>
<modify-wsdl-address>true</modify-wsdl-address>

Of course, when a confidential transport address is required, the addresses are always rewritten using https protocol and the port currently configured for the https/ssl connector.

5.4. Configuration through deployment descriptor

The jboss-webservices.xml deployment descriptor can be used to provide additional configuration for a given deployment. The expected location of it is:

  • META-INF/jboss-webservices.xml for EJB webservice deployments (JAR archives)

  • WEB-INF/jboss-webservices.xml for POJO webservice deployments and EJB webservice endpoints bundled in WAR archives

  • META-INF/jboss-webservices.xml for EAR archives containing webservices deployment archives.

In case of jboss-webservices.xml descriptor included in both EAR and included JAR/WAR archive, the contents of the descriptor included in the JAR/WAR archives override the contents of the descriptor in the parent EAR archive.

The structure of the file is the following (schemas are available here ):

<webservices>
  <context-root/>?
  <config-name/>?
  <config-file/>?
  <property>*
    <name/>
    <value/>
  </property>
  <port-component>*
    <ejb-name/>
    <port-component-name/>
    <port-component-uri/>?
    <auth-method/>?
    <transport-guarantee/>?
    <secure-wsdl-access/>?
  </port-component>
  <webservice-description>*
    <webservice-description-name/>
    <wsdl-publish-location/>?
  </webservice-description>
</webservices>

5.4.1. context-root element

Element <context-root> can be used to customize context root of webservices deployment.

<webservices>
  <context-root>foo</context-root>
</webservices>

5.4.2. config-name and config-file elements

Elements <config-name> and <config-file> can be used to associate any endpoint provided in the deployment with a given Predefined client and endpoint configurations . Endpoint configuration are either specified in the referenced config file or in the WildFly domain model (webservices subsystem). For further details on the endpoint configurations and their management in the domain model, please see the related documentation .

<webservices>
  <config-name>Standard WSSecurity Endpoint</config-name>
  <config-file>META-INF/custom.xml</config-file>
</webservices>

5.4.3. property element

<property> elements can be used to setup simple property values to configure the ws stack behavior. Allowed property names and values are mentioned in the guide under related topics.

<property>
  <name>prop.name</name>
  <value>prop.value</value>
</property>

5.4.4. component element

Element <port-component> can be used to customize EJB endpoint target URI or to configure security related properties.

<webservices>
  <port-component>
    <ejb-name>TestService</ejb-name>
    <port-component-name>TestServicePort</port-component-name>
    <port-component-uri>/*</port-component-uri>
    <auth-method>BASIC</auth-method>
    <transport-guarantee>NONE</transport-guarantee>
    <secure-wsdl-access>true</secure-wsdl-access>
  </port-component>
</webservices>

5.4.5. webservice-description element

Element <webservice-description> can be used to customize (override) webservice WSDL publish location.

<webservices>
  <webservice-description>
    <webservice-description-name>TestService</webservice-description-name>
    <wsdl-publish-location>file:///bar/foo.wsdl</wsdl-publish-location>
  </webservice-description>
</webservices>

5.5. Schema validation of SOAP messages

Apache CXF has a feature for validating incoming and outgoing SOAP messages on both client and server side. The validation is performed against the relevant schema in the endpoint wsdl contract (server side) or the wsdl contract used for building up the service proxy (client side).

Schema validation can be turned on programmatically on client side

((BindingProvider)proxy).getRequestContext().put("schema-validation-enabled", true);

or using the @org.apache.cxf.annotations.SchemaValidation annotation on server side

import jakarta.jws.WebService;
import org.apache.cxf.annotations.SchemaValidation;

@WebService(...)
@SchemaValidation
public class ValidatingHelloImpl implements Hello {
   ...
}

Alternatively, any endpoint and client running in-container can be associated to a JBossWS Predefined client and endpoint configurations having the schema-validation-enabled property set to true in the referenced config file.

Finally, JBossWS also allows for server-wide (default) setup of schema validation by using the Standard-Endpoint-Config and Standard-Client-Config special configurations (which apply to any client / endpoint unless a different configuration is specified for them)

<subsystem xmlns="urn:jboss:domain:webservices:1.2">
    ...
    <endpoint-config name="Standard-Endpoint-Config">
        <property name="schema-validation-enabled" value="true"/>
    </endpoint-config>
    ...
    <client-config name="Standard-Client-Config">
        <property name="schema-validation-enabled" value="true"/>
    </client-config>
</subsystem>

5.6. JAXB Introductions

One common complaint from the JAXB users is the lack of support for binding 3rd party classes. The scenario is this: you are trying to annotate your classes with JAXB annotations to make it XML bindable, but some classes are coming from libraries and JDK, and thus you cannot put necessary JAXB annotations on it.

To solve this JAXB has been designed to provide hooks for programmatic introduction of annotations to the runtime.

This is currently leveraged by the JBoss JAXB Introductions project, in which users can define annotations in XML and make JAXB see those as if those were in the class files (perhaps coming from 3rd party libraries).

Look at the JAXB Introductions page on the wiki and at the examples in the sources.

5.7. WSDL system properties expansion

5.8. Predefined client and endpoint configurations

5.8.1. Overview

JBossWS permits extra setup configuration data to be predefined and associated with an endpoint or a client. Configurations can include JAX-WS handlers and key/value property declarations that control JBossWS and Apache CXF internals. Predefined configurations can be used for JAX-WS client and JAX-WS endpoint setup.

Configurations can be defined in the webservice subsystem and in an application’s deployment descriptor file. There can be many configuration definitions in the webservice subsystem and in an application. Each configuration must have a name that is unique within the server. Configurations defined in an application are local to the application. Endpoint implementations declare the use of a specific configuration through the use of the org.jboss.ws.api.annotation.EndpointConfig annotation. An endpoint configuration defined in the webservices subsystem is available to all deployed applications on the server container and can be referenced by name in the annotation. An endpoint configuration defined in an application must be referenced by both deployment descriptor file name and configuration name by the annotation.

Handlers

Each endpoint configuration may be associated with zero or more PRE and POST handler chains. Each handler chain may include JAX-WS handlers. For outbound messages the PRE handler chains are executed before any handler that is attached to the endpoint using the standard means, such as with annotation @HandlerChain, and POST handler chains are executed after those objects have executed. For inbound messages the POST handler chains are executed before any handler that is attached to the endpoint using the standard means and the PRE handler chains are executed after those objects have executed.

* Server inbound messages
Client --> ... --> POST HANDLER --> ENDPOINT HANDLERS --> PRE HANDLERS --> Endpoint

* Server outbound messages
Endpoint --> PRE HANDLER --> ENDPOINT HANDLERS --> POST HANDLERS --> ... --> Client

The same applies for client configurations.

Properties

Key/value properties are used for controlling both some Apache CXF internals and some JBossWS options. Specific supported values are mentioned where relevant in the rest of the documentation.

5.8.2. Assigning configurations

Endpoints and clients are assigned configuration through different means. Users can explicitly require a given configuration or rely on container defaults. The assignment process can be split up as follows:

  • Explicit assignment through annotations (for endpoints) or API programmatic usage (for clients)

  • Automatic assignment of configurations from default descriptors

  • Automatic assignment of configurations from container

Explicit configuration assignment

The explicit configuration assignment is meant for developer that know in advance their endpoint or client has to be setup according to a specified configuration. The configuration is either coming from a descriptor that is included in the application deployment, or is included in the application server webservices subsystem management model.

Configuration Deployment Descriptor

Jakarta EE archives that can contain JAX-WS client and endpoint implementations can also contain predefined client and endpoint configuration declarations. All endpoint/client configuration definitions for a given archive must be provided in a single deployment descriptor file, which must be an implementation of schema jbossws-jaxws-config . Many endpoint/client configurations can be defined in the deployment descriptor file. Each configuration must have a name that is unique within the server on which the application is deployed. The configuration name can’t be referred to by endpoint/client implementations outside the application. Here is an example of a descriptor, containing two endpoint configurations:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jakartaee="xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.jbws3282.Endpoint4Impl</config-name>
    <pre-handler-chains>
      <jakartaee:handler-chain>
        <jakartaee:handler>
          <jakartaee:handler-name>Log Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.LogHandler</jakartaee:handler-class>
        </jakartaee:handler>
      </jakartaee:handler-chain>
    </pre-handler-chains>
    <post-handler-chains>
      <jakartaee:handler-chain>
        <jakartaee:handler>
          <jakartaee:handler-name>Routing Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.RoutingHandler</jakartaee:handler-class>
        </jakartaee:handler>
      </jakartaee:handler-chain>
    </post-handler-chains>
  </endpoint-config>
  <endpoint-config>
    <config-name>EP6-config</config-name>
    <post-handler-chains>
      <jakartaee:handler-chain>
        <jakartaee:handler>
          <jakartaee:handler-name>Authorization Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.jbws3282.AuthorizationHandler</jakartaee:handler-class>
        </jakartaee:handler>
      </jakartaee:handler-chain>
    </post-handler-chains>
  </endpoint-config>
</jaxws-config>

Similarly, client configurations can be specified in descriptors (still implementing the schema mentioned above):

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <client-config>
    <config-name>Custom Client Config</config-name>
    <pre-handler-chains>
      <jakartaee:handler-chain>
        <jakartaee:handler>
          <jakartaee:handler-name>Routing Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</jakartaee:handler-class>
        </jakartaee:handler>
        <jakartaee:handler>
          <jakartaee:handler-name>Custom Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.CustomHandler</jakartaee:handler-class>
        </jakartaee:handler>
      </jakartaee:handler-chain>
    </pre-handler-chains>
  </client-config>
  <client-config>
    <config-name>Another Client Config</config-name>
    <post-handler-chains>
      <jakartaee:handler-chain>
        <jakartaee:handler>
          <jakartaee:handler-name>Routing Handler</jakartaee:handler-name>
          <jakartaee:handler-class>org.jboss.test.ws.jaxws.clientConfig.RoutingHandler</jakartaee:handler-class>
        </jakartaee:handler>
      </jakartaee:handler-chain>
    </post-handler-chains>
  </client-config>
</jaxws-config>
Application server configurations

WildFly allows declaring JBossWS client and server predefined configurations in the webservices subsystem section of the server model. As a consequence it is possible to declare server-wide handlers to be added to the chain of each endpoint or client assigned to a given configuration.

Please refer to the WildFly documentation for details on managing the webservices subsystem such as adding, removing and modifying handlers and properties.

The allowed contents in the webservices subsystem are defined by the schema included in the application server.

  • Standard configurations

Clients running in-container as well as endpoints are assigned standard configurations by default. The defaults are used unless different configurations are set as described on this page. This enables administrators to tune the default handler chains for client and endpoint configurations. The names of the default client and endpoint configurations, used in the webservices subsystem are Standard-Client-Config and Standard-Endpoint-Config respectively.

  • Handlers classloading

When setting a server-wide handler, please note the handler class needs to be available through each ws deployment classloader. As a consequence proper module dependencies might need to be specified in the deployments that are going to leverage a given predefined configuration. A shortcut is to add a dependency to the module containing the handler class in one of the modules which are already automatically set as dependencies to any deployment, for instance org.jboss.ws.spi .

  • Examples

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
    <!-- ... -->
    <endpoint-config name="Standard-Endpoint-Config"/>
    <endpoint-config name="Recording-Endpoint-Config">
        <pre-handler-chain name="recording-handlers" protocol-bindings="##SOAP11_HTTP ##SOAP11_HTTP_MTOM ##SOAP12_HTTP ##SOAP12_HTTP_MTOM">
            <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
        </pre-handler-chain>
    </endpoint-config>
    <client-config name="Standard-Client-Config"/>
</subsystem>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>
<subsystem xmlns="urn:jboss:domain:webservices:2.0">
    <!-- ... -->
    <endpoint-config name="Standard-Endpoint-Config">
        <property name="schema-validation-enabled" value="true"/>
    </endpoint-config>
    <!-- ... -->
    <client-config name="Standard-Client-Config">
        <property name="schema-validation-enabled" value="true"/>
    </client-config>
</subsystem>
EndpointConfig annotation

Once a configuration is available to a given application, the org.jboss.ws.api.annotation.EndpointConfig annotation is used to assign an endpoint configuration to a JAX-WS endpoint implementation. When assigning a configuration that is defined in the webservices subsystem only the configuration name is specified. When assigning a configuration that is defined in the application, the relative path to the deployment descriptor and the configuration name must be specified.

@EndpointConfig(configFile = "WEB-INF/my-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
}
JAXWS Feature

The most practical way of setting a configuration is using org.jboss.ws.api.configuration.ClientConfigFeature , a JAX-WS Feature extension provided by JBossWS:

import org.jboss.ws.api.configuration.ClientConfigFeature;

...

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"));
port.echo("Kermit");

... or ....

port = service.getPort(Endpoint.class, new ClientConfigFeature("META-INF/my-client-config.xml", "Custom Client Config"), true); //setup properties too from the configuration
port.echo("Kermit");
... or ...

port = service.getPort(Endpoint.class, new ClientConfigFeature(null, testConfigName)); //reads from current container configurations if available
port.echo("Kermit");

JBossWS parses the specified configuration file. The configuration file must be found as a resource by the classloader of the current thread. The jbossws-jaxws-config schema defines the descriptor contents and is included in the jbossws-spi artifact.

Explicit setup through API

Alternatively, JBossWS API comes with facility classes that can be used for assigning configurations when building a client. JAX-WS handlers read from client configurations as follows:

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;

...

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);
BindingProvider bp = (BindingProvider)port;
ClientConfigUtil.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 1");
port.echo("Kermit");

...

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 2");
port.echo("Kermit");

...

configurer.setConfigHandlers(bp, "META-INF/my-client-config.xml", "Custom Client Config 3");
port.echo("Kermit");


...

configurer.setConfigHandlers(bp, null, "Container Custom Client Config"); //reads from current container configurations if available
port.echo("Kermit");
  1. similarly, properties are read from client configurations as follows:

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;

...

Service service = Service.create(wsdlURL, serviceName);
Endpoint port = service.getPort(Endpoint.class);

ClientConfigUtil.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 1");
port.echo("Kermit");

...

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 2");
port.echo("Kermit");

...

configurer.setConfigProperties(port, "META-INF/my-client-config.xml", "Custom Client Config 3");
port.echo("Kermit");


...

configurer.setConfigProperties(port, null, "Container Custom Client Config"); //reads from current container configurations if available
port.echo("Kermit");

The default ClientConfigurer implementation parses the specified configuration file, if any, after having resolved it as a resources using the current thread context classloader. The jbossws-jaxws-config schema defines the descriptor contents and is included in the jbossws-spi artifact.

Automatic configuration from default descriptors

In some cases, the application developer might not be aware of the configuration that will need to be used for its client and endpoint implementation, perhaps because that’s a concern of the application deployer. In other cases, explicit usage (compile time dependency) of JBossWS API might not be accepted. To cope with such scenarios, JBossWS allows including default client ( jaxws-client-config.xml ) and endpoint ( jaxws-endpoint-config.xml ) descriptor within the application (in its root), which are parsed for getting configurations any time a configuration file name is not specified.

If the configuration name is also not specified, JBossWS automatically looks for a configuration named the same as

  • the endpoint implementation class (full qualified name), in case of JAX-WS endpoints;

  • the service endpoint interface (full qualified name), in case of JAX-WS clients.

No automatic configuration name is selected for Dispatch clients.

So, for instance, an endpoint implementation class org.foo.bar.EndpointImpl for which no pre-defined configuration is explicitly set will cause JBossWS to look for a org.foo.bar.EndpointImpl named configuration within a jaxws-endpoint-config.xml descriptor in the root of the application deployment. Similarly, on the client side, a client proxy implementing org.foo.bar.Endpoint interface (SEI) will have the setup read from a org.foo.bar.Endpoint named configuration in jaxws-client-config.xml descriptor.

Automatic configuration assignment from container setup

JBossWS fall-backs to getting predefined configurations from the container setup whenever no explicit configuration has been provided and the default descriptors are either not available or do not contain relevant configurations. This gives additional control on the JAX-WS client and endpoint setup to administrators, as the container setup can be managed independently of the deployed applications.

JBossWS hence accesses the webservices subsystem the same as explained above for explicitly named configuration; the default configuration names used for look are

  • the endpoint implementation class (full qualified name), in case of JAX-WS endpoints;

  • the service endpoint interface (full qualified name), in case of JAX-WS clients.

Dispatch clients are not automatically configured. If no configuration is found using names computed as above, the Standard-Client-Config and Standard-Endpoint-Config configurations are used for clients and endpoints respectively

5.9. Authentication

5.9.1. Authentication

Here the simplest way to authenticate a web service user with JBossWS is explained.

First we secure the access to the SLSB as we would do for normal (non web service) invocations: this can be easily done through the @RolesAllowed, @PermitAll, @DenyAll annotation. 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
{
  ...
}

Similarly POJO endpoints are secured the same way as we do for normal web applications in web.xml:

<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>
Specify the security domain

Next, specify the security domain for this deployment. This is performed using the @SecurityDomain annotation for EJB3 endpoints

@Stateless
@SecurityDomain("JBossWS")
@RolesAllowed("friend")
public class EndpointEJB implements EndpointInterface
{
  ...
}

or modifying the jboss-web.xml for POJO endpoints

<jboss-web>
<security-domain>JBossWS</security-domain>
</jboss-web>

The security domain is the authentication and authorization mechanism. Security domains are defined differently depending on the server in use.

Use BindingProvider to set principal/credential

A web service client may use the jakarta.xml.ws.BindingProvider interface to set the username/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, "kermit");
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "thefrog");
Using HTTP Basic Auth for security

To enable HTTP Basic authentication use the @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
{
  ...
}

For POJO endpoints, we modify the web.xml adding the auth-method element:

<login-config>
  <auth-method>BASIC</auth-method>
  <realm-name>Test Realm</realm-name>
</login-config>

5.10. Apache CXF integration

5.10.1. JBossWS integration layer with Apache CXF

All JAX-WS functionalities provided by JBossWS on top of WildFly are currently served through a proper integration of the JBoss Web Services stack with most of the Apache CXF project modules.

Apache CXF is an open source services framework. It allows building and developing services using frontend programming APIs (including JAX-WS), with services speaking a variety of protocols such as SOAP and XML/HTTP over a variety of transports such as HTTP and JMS.

The integration layer ( JBossWS-CXF in short hereafter) is mainly meant for:

  • allowing using standard webservices APIs (including JAX-WS) on WildFly; 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 WildFly 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 JBoss ws endpoint deployment mechanism and comes with many internal customizations on top of Apache CXF.

In the next sections a list of technical suggestions and notes on the integration is provided; please also refer to the Apache CXF official documentation for in-depth details on the CXF architecture.

5.10.2. Building WS applications the JBoss way

The Apache CXF client and endpoint configuration as explained in the Apache CXF official user guide is heavily based on Spring. Apache CXF basically parses Spring cxf.xml descriptors; those may contain any basic bean plus specific ws client and endpoint beans which CXF has custom parsers for. Apache CXF can be used to deploy webservice endpoints on any servlet container by including its libraries in the deployment; in such a scenario Spring basically serves as a convenient configuration option, given direct Apache CXF API usage won’t be very handy. Similar reasoning applies on client side, where a Spring based descriptor offers to a shortcut for setting up Apache CXF internals.

This said, nowadays almost any Apache CXF functionality can be configured and used through direct API usage, without Spring. As a consequence and given the considerations in the sections below, the JBossWS integration with Apache CXF does not rely on Spring descriptors.

Portable applications

WildFly is much more then a servlet container; it actually provides users with a fully compliant target platform for Java EE applications.

Generally speaking, users are encouraged to write portable applications by relying only on JAX-WS specification whenever possible, that would by the way ensure easy migrations to and from other compliant platforms. Being a Java EE container, WildFly already comes with a JAX-WS compliant implementation, which is basically Apache CXF plus the JBossWS-CXF integration layer. So users just need to write their JAX-WS application; no need for embedding any Apache CXF or any ws related dependency library in user deployments . Please refer to the Advanced User Guide of the documentation for getting started.

WS-* usage (including WS-Security, WS-Addressing, WS-ReliableMessaging, …​) should also be configured in the most portable way; that is by relying on proper WS-Policy assertions on the endpoint WSDL contracts, so that client and endpoint configuration is basically a matter of setting few ws context properties. The WS-* related sections of this documentation cover all the details on configuring applications making use of WS-* through policies.

As a consequence of the reasoning above, the JBossWS-CXF integration is currently built directly on the Apache CXF API and aims at allowing users to configure webservice clients and endpoints without Spring descriptors .

Direct Apache CXF API usage

Whenever users can’t meet their application requirements with JAX-WS plus WS-Policy, it is still possible to rely on direct Apache CXF API usage (given that’s included in the AS). The transition to Jakarta EE could affect portability of newer applications to legacy systems, that could be the case of a user needing specific Apache CXF functionalities, or having to consume WS-* enabled endpoints advertised through legacy wsdl contracts without WS-Policy assertions.

On server side, direct Apache CXF API usage might not always be possible or end up being not very easy. For this reason, the JBossWS integration comes with a convenient alternative through customization options in the jboss-webservices.xml descriptor described below on this page. Properties can be declared in jboss-webservices.xml to control Apache CXF internals like interceptors , features , etc.

5.10.3. Bus usage

Creating a Bus instance

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, looking for optional configurations in META-INF/services/…​ location using the current thread context classloader. JBossWS-CXF integration comes with its own implementation of BusFactory , org.jboss.wsf.stack.cxf.client.configuration.JBossWSBusFactory , that allows for seamless setup of JBossWS customizations on top of Apache CXF. 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 explicitly use functionalities of org.apache.cxf.bus.CXFBusFactory , get the same API with JBossWS additions through JBossWSBusFactory :

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 trying to create a new instance (and the created new instance is set as global default bus if it is not yet set).

The drawback of this mechanism (which is fine in JSE environment) is that when running in the WildFly 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 WildFly).

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 customizing a thread default bus instance (for instance adding bus scope interceptors, …​), as that thread and bus might be later reused; 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 JAX-WS Provider implementation also creates Bus instances internally, in particular the JBossWS version of JAX-WS Provider makes sure the default bus is never internally used and instead a new Bus is created if required (more details on this in the next paragraph).

Bus selection strategies for JAXWS clients

JAX-WS clients require an Apache CXF Bus to be available; the client is registered within the Bus and the Bus affects the client behavior (e.g. through the configured CXF interceptors). The way a bus is internally selected for serving a given JAX-WS client is very important, especially for in-container clients; for this reason, JBossWS users can choose the preferred Bus selection strategy. The strategy is enforced in the jakarta.xml.ws.spi.Provider implementation from the JBossWS integration, being that called whenever a JAX-WS Service (client) is requested.

Thread bus strategy (THREAD_BUS)

Each time the vanilla JAX-WS api is used to create a Bus, the JBossWS-CXF integration will automatically make sure a Bus is currently associated to the current thread in the BusFactory. If that’s not the case, a new Bus is created and linked to the current thread (to prevent the user from relying on the default Bus). The Apache CXF engine will then create the client using the current thread Bus.

This is the default strategy, and the most straightforward one in Java SE environments; it lets users automatically reuse a previously created Bus instance and allows using customized Bus that can possibly be created and associated to the thread before building up a JAX-WS client.

The drawback of the strategy is that the link between the Bus instance and the thread needs to be eventually cleaned up (when not needed anymore). This is really evident in a Jakarta EE environment (hence when running in-container), as threads from pools (e.g. serving web requests) are re-used.

When relying on this strategy, the safest approach to be sure of cleaning up the link is to surround the JAX-WS client with a try/finally block as below:

try {
  Service service = Service.create(wsdlURL, serviceQName);
  MyEndpoint port = service.getPort(MyEndpoint.class);
  //...
} finally {
  BusFactory.setThreadDefaultBus(null);
  // OR (if you don't need the bus and the client anymore)
  Bus bus = BusFactory.getThreadDefaultBus(false);
  bus.shutdown(true);
}
New bus strategy (NEW_BUS)

Another strategy is to have the JAX-WS Provider from the JBossWS integration create a new Bus each time a JAX-WS client is built. The main benefit of this approach is that a fresh bus won’t rely on any formerly cached information (e.g. cached WSDL / schemas) which might have changed after the previous client creation. The main drawback is of course worse performance as the Bus creation takes time.

If there’s a bus already associated with the current thread before the JAX-WS client creation, that is automatically restored when returning control to the user; in other words, the newly created bus will be used only for the created JAX-WS client but won’t stay associated with the current thread at the end of the process. Similarly, if the thread was not associated with any bus before the client creation, no bus will be associated with the thread at the end of the client creation.

Thread context classloader bus strategy (TCCL_BUS)

The last strategy is to have the bus created for serving the client be associated with the current thread context classloader (TCCL). That basically means, the same Bus instance is shared by JAX-WS clients running when the same TCCL is set. This is particularly interesting as each web application deployment usually has its own context classloader. This strategy is possibly a way to keep the number of created Bus instances bound to the application number in a WildFly container.

If there’s a bus already associated with the current thread before the JAX-WS client creation, that is automatically restored when returning control to the user; in other words, the bus corresponding to the current thread context classloader will be used only for the created JAX-WS client but won’t stay associated with the current thread at the end of the process. If the thread was not associated with any bus before the client creation, a new bus will be created (and later user for any other client built with this strategy and the same TCCL in place); no bus will be associated with the thread at the end of the client creation.

Strategy configuration

Users can request a given Bus selection strategy to be used for the client being built by specifying one of the following JBossWS features (which extend jakarta.xml.ws.WebServiceFeature ):

Feature Strategy

org.jboss.wsf.stack.cxf.client.UseThreadBusFeature

THREAD_BUS

org.jboss.wsf.stack.cxf.client.UseNewBusFeature

NEW_BUS

org.jboss.wsf.stack.cxf.client.UseTCCLBusFeature

TCCL_BUS

The feature is specified as follows:

Service service = Service.create(wsdlURL, serviceQName, new UseThreadBusFeature());

If no feature is explicitly specified, the system default strategy is used, which can be modified through the org.jboss.ws.cxf.jaxws-client.bus.strategy system property when starting the JVM. The valid values for the property are THREAD_BUS , NEW_BUS and TCCL_BUS . The default is THREAD_BUS .

5.10.4. 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 provided ws deployment. Should the deployment include multiple endpoints, those would all live within the same Apache CXF Bus, which would be completely separated by the other deployments' bus instances.

While JBossWS sets sensible defaults for most of the Apache CXF configuration options on server side, users might want to fine tune the Bus instance that’s created for their deployment; a jboss-webservices.xml descriptor can be used for deployment level customizations.

Deployment descriptor properties

The jboss-webservices.xml descriptor can be used to provide property values for component element

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  ...
  <property>
    <name>...</name>
    <value>...</value>
  </property>
  ...
</webservices>

JBossWS-CXF integration comes with a set of allowed property names to control Apache CXF internals.

WorkQueue configuration

Apache CXF uses WorkQueue instances for dealing with some operations (e.g. @Oneway requests processing). A WorkQueueManager is installed in the Bus as an extension and allows for adding / removing queues as well as controlling the existing ones.

On server side, queues can be provided by using the cxf.queue.<queue-name>.* properties in jboss-webservices.xml (e.g. cxf.queue.default.maxQueueSize for controlling the max queue size of the default workqueue). At deployment time, the JBossWS integration can add new instances of AutomaticWorkQueueImpl to the currently configured WorkQueueManager; the properties below are used to fill in parameter into the AutomaticWorkQueueImpl constructor :

Property Default value

cxf.queue.<queue-name>.maxQueueSize

256

cxf.queue.<queue-name>.initialThreads

0

cxf.queue.<queue-name>.highWaterMark

25

cxf.queue.<queue-name>.lowWaterMark

5

cxf.queue.<queue-name>.dequeueTimeout

120000

Policy alternative selector

The Apache CXF policy engine supports different strategies to deal with policy alternatives. JBossWS-CXF integration currently defaults to the MaximalAlternativeSelector , but still allows for setting different selector implementation using the cxf.policy.alternativeSelector property in jboss-webservices.xml .

MBean management

Apache CXF allows managing its MBean objects that are installed into the WildFly MBean server. The feature is enabled on a deployment basis through the cxf.management.enabled property in jboss-webservices.xml . The cxf.management.installResponseTimeInterceptors property can also be used to control installation of CXF response time interceptors, which are added by default when enabling MBean management, but might not be desired in some cases. Here is an example:

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" version="1.2">
  <property>
    <name>cxf.management.enabled</name>
    <value>true</value>
  </property>
  <property>
    <name>cxf.management.installResponseTimeInterceptors</name>
    <value>false</value>
  </property>
</webservices>
Schema validation

Schema validation of exchanged messages can also be enabled in jboss-webservices.xml . Further details available Configuration through deployment descriptor

Interceptors

The jboss-webservices.xml descriptor also allows specifying the cxf.interceptors.in and cxf.interceptors.out properties; those allows declaring interceptors to be attached to the Bus instance that’s created for serving the deployment.

<?xml version="1.1" encoding="UTF-8"?>
<webservices
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.3"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">

  <property>
    <name>cxf.interceptors.in</name>
    <value>org.jboss.test.ws.jaxws.cxf.interceptors.BusInterceptor</value>
  </property>
  <property>
    <name>cxf.interceptors.out</name>
    <value>org.jboss.test.ws.jaxws.cxf.interceptors.BusCounterInterceptor</value>
  </property>
</webservices>
Features

The jboss-webservices.xml descriptor also allows specifying the cxf.features property; that allows declaring features to be attached to any endpoint belonging to the Bus instance that’s created for serving the deployment.

<?xml version="1.1" encoding="UTF-8"?>
<webservices
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.3"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">

  <property>
    <name>cxf.features</name>
    <value>org.apache.cxf.feature.FastInfosetFeature</value>
  </property>
</webservices>
Discovery enablement

WS-Discovery support can be turned on in jboss-webservices for the current deployment. Further details available Configuration through deployment descriptor .

5.10.5. Apache CXF interceptors

Apache CXF supports declaring interceptors using one of the following approaches:

  • Annotation usage on endpoint classes ( @org.apache.cxf.interceptor.InInterceptor , @org.apache.cxf.interceptor.OutInterceptor )

  • Direct API usage on client side (through the org.apache.cxf.interceptor.InterceptorProvider interface)

  • Spring descriptor usage ( cxf.xml )

As the Spring descriptor usage is not supported, the JBossWS integration adds an additional descriptor based approach to avoid requiring modifications to the actual client/endpoint code. Users can declare interceptors within Predefined client and endpoint configurations by specifying a list of interceptor class names for the cxf.interceptors.in and cxf.interceptors.out properties.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointImpl</config-name>
    <property>
      <property-name>cxf.interceptors.in</property-name>
      <property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointInterceptor,org.jboss.test.ws.jaxws.cxf.interceptors.FooInterceptor</property-value>
    </property>
    <property>
      <property-name>cxf.interceptors.out</property-name>
      <property-value>org.jboss.test.ws.jaxws.cxf.interceptors.EndpointCounterInterceptor</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

A new instance of each specified interceptor class will be added to the client or endpoint the configuration is assigned to. The interceptor classes must have a no-argument constructor.

5.10.6. Apache CXF features

Apache CXF supports declaring features using one of the following approaches:

  • Annotation usage on endpoint classes ( @org.apache.cxf.feature.Features )

  • Direct API usage on client side (through extensions of the org.apache.cxf.feature.AbstractFeature class)

  • Spring descriptor usage ( cxf.xml )

As the Spring descriptor usage is not supported, the JBossWS integration adds a descriptor based approach to avoid requiring modifications to the actual client/endpoint code. Users can declare features by specifying a list of feature class names for the cxf.features property.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>Custom FI Config</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>org.apache.cxf.feature.FastInfosetFeature</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

A new instance of each specified feature class will be added to the client or endpoint the configuration is assigned to. The feature classes must have a no-argument constructor.

5.10.7. Properties driven bean creation

Sections above explain how to declare CXF interceptors and features through properties either in a client/endpoint predefined configuration or in a jboss-webservices.xml descriptor. By getting the feature/interceptor class name only specified, the container simply tries to create a bean instance using the class default constructor. This sets a limitation on the feature/interceptor configuration, unless custom extensions of vanilla CXF classes are provided, with the default constructor setting properties before eventually using the super constructor.

To cope with this issue, JBossWS integration comes with a mechanism for configuring simple bean hierarchies when building them up from properties. Properties can have bean reference values, that is strings starting with ## . Property reference keys are used to specify the bean class name and the value for each attribute. So for instance the following properties:

Key Value

cxf.features

foo, bar

##foo

org.jboss.Foo

##foo.par

34

##bar

org.jboss.Bar

##bar.color

blue

would result into the stack installing two feature instances, the same that would have been created by

import org.Bar;
import org.Foo;

...

Foo foo = new Foo();
foo.setPar(34);
Bar bar = new Bar();
bar.setColor("blue");

The mechanism assumes that the classes are valid beans with proper getter and setter methods; value objects are cast to the correct primitive type by inspecting the class definition. Nested beans can of course be configured.

5.10.8. HTTPConduit configuration

HTTP transport setup in Apache CXF is achieved through org.apache.cxf.transport.http.HTTPConduit configurations . When running on top of the JBossWS integration, conduits can be programmatically modified using the Apache CXF API as follows:

import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

//set chunking threshold before using a JAX-WS port client
...
HTTPConduit conduit = (HTTPConduit)ClientProxy.getClient(port).getConduit();
HTTPClientPolicy client = conduit.getClient();

client.setChunkingThreshold(8192);
...

Users can also control the default values for the most common HTTPConduit parameters by setting specific system properties; the provided values will override Apache CXF defaut values.

Property Description

cxf.client.allowChunking

A boolean to tell Apache CXF whether to allow send messages using chunking.

cxf.client.chunkingThreshold

An integer value to tell Apache CXF the threshold at which switching from non-chunking to chunking mode.

cxf.client.connectionTimeout

A long value to tell Apache CXF how many milliseconds to set the connection timeout to

cxf.client.receiveTimeout

A long value to tell Apache CXF how many milliseconds to set the receive timeout to

cxf.client.connection

A string to tell Apache CXF to use Keep-Alive or close connection type

cxf.tls-client.disableCNCheck

A boolean to tell Apache CXF whether disabling CN host name check or not

The vanilla Apache CXF defaults apply when the system properties above are not set.

5.11. Addressing

JBoss Web Services inherits full WS-Addressing capabilities from the underlying Apache CXF implementation. Apache CXF provides support for 2004-08 and 1.0 versions of WS-Addressing.

5.11.1. Enabling WS-Addressing

WS-Addressing can be turned on in multiple standard ways:

  • consuming a WSDL contract that specifies a WS-Addressing assertion / policy

  • using the @jakarta.xml.ws.soap.Addressing annotation

  • using the jakarta.xml.ws.soap.AddressingFeature feature

Important

The supported addressing policy elements are:

[http://www.w3.org/2005/02/addressing/wsdl]UsingAddressing
[http://schemas.xmlsoap.org/ws/2004/08/addressing/policy]UsingAddressing
[http://www.w3.org/2006/05/addressing/wsdl]UsingAddressing
[http://www.w3.org/2007/05/addressing/metadata]Addressing

Alternatively, Apache CXF proprietary ways are also available:

  • specifying the [http://cxf.apache.org/ws/addressing]addressing feature for a given client/endpoint

  • using the org.apache.cxf.ws.addressing.WSAddressingFeature feature through the API

  • manually configuring the Apache CXF addressing interceptors ( org.apache.cxf.ws.addressing.MAPAggregator and org.apache.cxf.ws.addressing.soap.MAPCodec )

  • setting the org.apache.cxf.ws.addressing.using property in the message context

Please refer to the Apache CXF documentation for further information on the proprietary WS-Addressing setup and configuration details .

5.11.2. Addressing Policy

The WS-Addressing support is also perfectly integrated with the Apache CXF WS-Policy engine.

This basically means that the WSDL contract generation for code-first endpoint deployment is policy-aware: users can annotate endpoints with the @jakarta.xml.ws.soap.Addressing annotation and expect the published WSDL contract to contain proper WS-Addressing policy (assuming no wsdlLocation is specified in the endpoint’s @WebService annotation).

Similarly, on client side users do not need to manually specify the jakarta.xml.ws.soap.AddressingFeature feature, as the policy engine is able to properly process the WS-Addressing policy in the consumed WSDL and turn on addressing as requested.

5.11.3. Example

Here is an example showing how to enable WS-Addressing through WS-Policy.

Endpoint

A simple JAX-WS endpoint is prepared using a java-first approach; WS-Addressing is enforced through @Addressing annotation and no wsdlLocation is provided in @WebService :

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

import jakarta.jws.WebService;
import jakarta.xml.ws.soap.Addressing;
import org.jboss.logging.Logger;

@WebService
(
   portName = "AddressingServicePort",
   serviceName = "AddressingService",
   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
{
   private Logger log = Logger.getLogger(this.getClass());

   public String sayHello(String name)
   {
      return "Hello " + name + "!";
   }
}

The WSDL contract that’s generated at deploy time and published looks like this:

<wsdl:definitions ....>
...
  <wsdl:binding name="AddressingServiceSoapBinding" type="tns:ServiceIface">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsaw:UsingAddressing wsdl:required="true"/>
    <wsp:PolicyReference URI="#AddressingServiceSoapBinding_WSAM_Addressing_Policy"/>

    <wsdl:operation name="sayHello">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="sayHello">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="sayHelloResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>

  </wsdl:binding>
  <wsdl:service name="AddressingService">
    <wsdl:port binding="tns:AddressingServiceSoapBinding" name="AddressingServicePort">
      <soap:address location="http://localhost:8080/jaxws-samples-wsa"/>
    </wsdl:port>
  </wsdl:service>
    <wsp:Policy wsu:Id="AddressingServiceSoapBinding_WSAM_Addressing_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/05/addressing/metadata">
        <wsp:Policy/>
      </wsam:Addressing>
    </wsp:Policy>
</wsdl:definitions>
Client

Since the WS-Policy engine is on by default, the client side code is a pure JAX-WS client app:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsaddressing", "AddressingService");
URL wsdlURL = new URL("http://localhost:8080/jaxws-samples-wsa?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);
proxy.sayHello("World");

5.12. WS-Security

5.12.1. WS-Security overview

WS-Security provides the means to secure your services beyond transport level protocols such as 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.

WS-Security makes heavy use of public and private key cryptography. It is helpful to understand the basics to understand how to configure WS-Security. With public key cryptography, a user has a pair of public and private keys. These are generated using a large prime number and a key function.

Public key making

The keys are related mathematically, but cannot be derived from one another. With these keys we can encrypt messages. For example, if Bob wants to send a message to Alice, he can encrypt a message using her public key. Alice can then decrypt this message using her private key. Only Alice can decrypt this message as she is the only one with the private key.

Public key encryption mod.svg

Messages can also be signed. This allows you to ensure the authenticity of the message. If Alice wants to send a message to Bob, and Bob wants to be sure that it is from Alice, Alice can sign the message using her private key. Bob can then verify that the message is from Alice by using her public key.

250px Public key making.svg

5.12.2. JBoss WS-Security support

JBoss Web Services supports many real world scenarios requiring WS-Security functionalities. This includes signature and encryption support through X509 certificates, authentication and authorization through username tokens as well as all ws-security configurations covered by WS- SecurityPolicy specification.

As well as for other WS-* features , the core of WS-Security functionalities is provided through the Apache CXF engine. On top of that the JBossWS integration adds few configuration enhancements to simplify the setup of WS-Security enabled endpoints.

Apache CXF WS-Security implementation

Apache CXF features a top class WS-Security module supporting multiple configurations and easily extendable.

The system is based on interceptors that delegate to Apache WSS4J for the low level security operations. Interceptors can be configured in different ways, either through Spring configuration files or directly using Apache CXF client API. Please refer to the Apache CXF documentation if you’re looking for more details.

Recent versions of Apache CXF, however, introduced support for WS-Security Policy, which aims at moving most of the security configuration into the service contract (through policies), so that clients can easily be configured almost completely automatically from that. This way users do not need to manually deal with configuring / installing the required interceptors; the Apache CXF WS-Policy engine internally takes care of that instead.

WS-Security Policy support

WS-SecurityPolicy describes the actions that are required to securely communicate with a service advertised in a given WSDL contract. The WSDL bindings / operations reference WS-Policy fragments with the security requirements to interact with the service. The WS-SecurityPolicy specification allows for specifying things like asymmetric/symmetric keys, using transports (https) for encryption, which parts/headers to encrypt or sign, whether to sign then encrypt or encrypt then sign, whether to include timestamps, whether to use derived keys, etc.

Some mandatory configuration elements are not covered by WS-SecurityPolicy, because they’re not meant to be a public / part of the published endpoint contract; those include things such as keystore locations, usernames and passwords, etc. Apache CXF allows configuring these elements either through Spring xml descriptors or using the client API / annotations. Below is the list of supported configuration properties:

ws-security.username The username used for UsernameToken policy assertions

ws-security.password

The password used for UsernameToken policy assertions. If not specified, the callback handler will be called.

ws-security.callback-handler

The WSS4J security CallbackHandler that will be used to retrieve passwords for keystores and UsernameTokens.

ws-security.signature.properties

The properties file/object that contains the WSS4J properties for configuring the signature keystore and crypto objects

ws-security.encryption.properties

The properties file/object that contains the WSS4J properties for configuring the encryption keystore and crypto objects

ws-security.signature.username

The username or alias for the key in the signature keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that’s also not set, and the keystore only contains a single key, that key will be used.

ws-security.encryption.username

The username or alias for the key in the encryption keystore that will be used. If not specified, it uses the the default alias set in the properties file. If that’s also not set, and the keystore only contains a single key, that key will be used. For the web service provider, the useReqSigCert keyword can be used to accept (encrypt to) any client whose public key is in the service’s truststore (defined in ws-security.encryption.properties.)

ws-security.signature.crypto

Instead of specifying the signature properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information."

ws-security.encryption.crypto

Instead of specifying the encryption properties, this can point to the full WSS4J Crypto object. This can allow easier "programmatic" configuration of the Crypto information."

ws-security.enable.streaming

Enable streaming (StAX based) processing of WS-Security messages

Here is an example of configuration using the client API:

Map<String, Object> ctx = ((BindingProvider)port).getRequestContext();
ctx.put("ws-security.encryption.properties", properties);
port.echoString("hello");

Please refer to the Apache CXF documentation for additional configuration details.

JBossWS configuration additions

In order for removing the need of Spring on server side for setting up WS-Security configuration properties not covered by policies, the JBossWS integration allows for getting those pieces of information from a defined endpoint configuration . Predefined client and endpoint configurations can include property declarations and endpoint implementations can be associated with a given endpoint configuration using the @EndpointConfig annotation.

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>
import jakarta.jws.WebService;
import org.jboss.ws.api.annotation.EndpointConfig;

@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
}
Apache CXF annotations

The JBossWS configuration additions allow for a descriptor approach to the WS-Security Policy engine configuration. If you prefer to provide the same information through an annotation approach, you can leverage the Apache CXF @org.apache.cxf.annotations.EndpointProperties annotation:

@WebService(
   ...
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.properties", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.signature.username", value = "bob"),
      @EndpointProperty(key = "ws-security.encryption.username", value = "alice"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback")
      }
)
public class ServiceImpl implements ServiceIface {
   ...
}

5.12.3. Examples

In this section a sample of WS-Security service endpoints and clients are provided. Please note they’re only meant as tutorials; you should careful isolate the ws-security policies / assertion that best suite your security needs before going to a production environment.

Warning

The following sections provide directions and examples on understanding some of the configuration options for WS-Security engine. Please note the implementor remains responsible for assessing the application requirements and choosing the most suitable security policy for them.

Signature and encryption
Endpoint

First, you need to create the web service endpoint using JAX-WS. While this can generally be achieved in different ways, it’s required to use a contract-first approach when using WS-Security, as the policies declared in the wsdl are parsed by the Apache CXF engine on both server and client sides. Here is an example of WSDL contract enforcing signature and encryption using X 509 certificates (the referenced schema is omitted):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing"
        xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#SecurityServiceSignThenEncryptPolicy"/>
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://localhost:8080/jaxws-samples-wssePolicy-sign-encrypt"/>
    </port>
  </service>

  <wsp:Policy wsu:Id="SecurityServiceSignThenEncryptPolicy" 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:WssX509V1Token11/>
                  </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/Never">
                  <wsp:Policy>
                    <sp:WssX509V1Token11/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:RecipientToken>
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:TripleDesRsa15/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:EncryptSignature/>
            <sp:OnlySignEntireHeadersAndBody/>
            <sp:SignBeforeEncrypting/>
          </wsp:Policy>
        </sp:AsymmetricBinding>
        <sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <sp:Body/>
        </sp:SignedParts>
        <sp:EncryptedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <sp:Body/>
        </sp:EncryptedParts>
        <sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial/>
          </wsp:Policy>
        </sp:Wss10>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>
</definitions>

The service endpoint can be generated using the wsconsume tool and then enriched with a @EndpointConfig annotation:

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

import jakarta.jws.WebService;
import org.jboss.ws.api.annotation.EndpointConfig;

@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }
}

The referenced jaxws-endpoint-config.xml descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; this tells the engine which certificate / key to use for signature / signature verification and for encryption / decryption:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.signature.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.properties</property-name>
      <property-value>bob.properties</property-value>
    </property>
    <property>
      <property-name>ws-security.signature.username</property-name>
      <property-value>bob</property-value>
    </property>
    <property>
      <property-name>ws-security.encryption.username</property-name>
      <property-value>alice</property-value>
    </property>
    <property>
      <property-name>ws-security.callback-handler</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.KeystorePasswordCallback</property-value>
    </property>
  </endpoint-config>
</jaxws-config>
  1. the bob.properties configuration file is also referenced above; it includes the WSS4J Crypto properties which in turn link to the keystore file, type and the alias/password to use for accessing it:

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.keystore.file=bob.jks

A callback handler for the letting Apache CXF access the keystore is also provided:

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

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");
   }

   /**
    * It attempts to get the password from the private
    * alias/passwords map.
    */
   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.getIdentifier());
         if (pass != null) {
            pc.setPassword(pass);
            return;
         }
      }
   }

   /**
    * Add an alias/password pair to the callback mechanism.
    */
   public void setAliasPassword(String alias, String password) {
      passwords.put(alias, password);
   }
}

Assuming the bob.jks keystore has been properly generated and contains Bob’s (server) full key (private/certificate + public key) as well as Alice’s (client) public key, we can proceed to packaging the endpoint. Here is the expected content (the endpoint is a POJO one in a war archive, but EJB3 endpoints in jar archives are of course also supported):

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-sign-encrypt.war
     0 Thu Jun 16 18:50:48 CEST 2011 META-INF/
   140 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/
   586 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/
  1687 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/KeystorePasswordCallback.class
   383 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceIface.class
  1070 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/basic/ServiceImpl.class
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/
   705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class
  1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class
  1225 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml
     0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/
  4086 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl
   653 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd
  1820 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.jks
   311 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/classes/bob.properties

The jaxws classes generated by the tools are included, as well as a basic web.xml referencing the endpoint bean:

<?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>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>
Important

If you’re deploying the endpoint archive to WildFly, remember to add a dependency to org.apache.ws.security module in the MANIFEST.MF file.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 17.0-b16 (Sun Microsystems Inc.)
Dependencies: org.apache.ws.security
Client

Start by consuming the published WSDL contract using the wsconsume tool on client side, then simply invoke the endpoint as a standard JAX-WS one:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);

((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"));
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.SIGNATURE_USERNAME, "alice");
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.ENCRYPT_USERNAME, "bob");

proxy.sayHello();

The WS-Security properties are set in the request context. Here the KeystorePasswordCallback is the same as on the server side above, you might want/need different implementation in real world scenarios. The alice.properties file is the client side equivalent of the server side bob.properties and references the alice.jks keystore file, which has been populated with Alice’s (client) full key (private/certificate + public key) as well as Bob’s (server) public key.

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=alice
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/alice.jks

The Apache CXF WS-Policy engine will digest the security requirements in the contract and ensure a valid secure communication is in place for interacting with the server endpoint.

Endpoint serving multiple clients

The server side configuration described above implies the endpoint is configured for serving a given client which a service agreement has been established for. In some real world scenarios, the same server might be expected to be able to deal with (including decrypting and encrypting) messages coming from and being sent to multiple clients. Apache CXF supports that through the useReqSigCert value for the ws-security.encryption.username configuration parameter.

Of course the referenced server side keystore needs to contain the public key of all the clients that are expected to be served.

Authentication and authorization

The Username Token Profile can be used to provide client’s credentials to a WS-Security enabled target endpoint.

Apache CXF provides a means for setting basic password callback handlers on both client and server sides to set/check passwords; the ws-security.username and ws-security.callback-handler properties can be used similarly as shown in the signature and encryption example. Things become more interesting when requiring a given user to be authenticated (and authorized) against a security domain on the target WildFly server.

On the server side, you need to install two additional interceptors that act as bridges for the application server authentication layer:

  • an interceptor for performing authentication and populating a valid SecurityContext; the provided interceptor should extend org.apache.cxf.ws.interceptor.security.AbstractUsernameTokenInInterceptor, 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.

Here follows an example of WS-SecurityPolicy endpoint using Username Token Profile for authenticating through the WildFly security domain system.

Endpoint

As in the other example, we start with a wsdl contract containing the proper WS-Security Policy:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <message name="greetMe">
    <part name="parameters" element="tns:greetMe"/>
  </message>
  <message name="greetMeResponse">
    <part name="parameters" element="tns:greetMeResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
    <operation name="greetMe">
      <input message="tns:greetMe"/>
      <output message="tns:greetMeResponse"/>
    </operation>
  </portType>
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#SecurityServiceUsernameUnsecureTransportPolicy"/>
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
    <operation name="greetMe">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://localhost:8080/jaxws-samples-wsse-username-jaas"/>
    </port>
  </service>

  <wsp:Policy wsu:Id="SecurityServiceUsernameUnsecureTransportPolicy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                    <wsp:Policy>
                        <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                            <wsp:Policy>
                                <sp:WssUsernameToken10/>
                            </wsp:Policy>
                        </sp:UsernameToken>
                    </wsp:Policy>
                </sp:SupportingTokens>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>

</definitions>
Important

If you want to send hash / digest passwords, you can use a policy such as what follows:

<wsp:Policy wsu:Id="SecurityServiceUsernameHashPasswordPolicy">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                <wsp:Policy>
                    <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                            <sp:HashPassword/>
                        </wsp:Policy>
                    </sp:UsernameToken>
                </wsp:Policy>
            </sp:SupportingTokens>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

Please note the specified JBoss security domain needs to be properly configured for computing digests.

The service endpoint can be generated using the wsconsume tool and then enriched with a @EndpointConfig annotation and @InInterceptors annotation to add the two interceptors mentioned above for JAAS integration:

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

import jakarta.jws.WebService;
import org.apache.cxf.interceptor.InInterceptors;
import org.jboss.ws.api.annotation.EndpointConfig;

@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceIface"
)
@EndpointConfig(configFile = "WEB-INF/jaxws-endpoint-config.xml", configName = "Custom WS-Security Endpoint")
@InInterceptors(interceptors = {
      "org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor",
      "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.POJOEndpointAuthorizationInterceptor"}
)
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "Secure Hello World!";
   }

   public String greetMe()
   {
      return "Greetings!";
   }
}

The POJOEndpointAuthorizationInterceptor is included into the deployment and deals with the roles cheks:

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

import java.util.HashMap;
import java.util.Map;
import org.apache.cxf.interceptor.security.SimpleAuthorizingInterceptor;

public class POJOEndpointAuthorizationInterceptor extends SimpleAuthorizingInterceptor
{

   public POJOEndpointAuthorizationInterceptor()
   {
      super();
      readRoles();
   }

   private void readRoles()
   {
      //just an example, this might read from a configuration file or such
      Map<String, String> roles = new HashMap<String, String>();
      roles.put("sayHello", "friend");
      roles.put("greetMe", "snoopies");
      setMethodRolesMap(roles);
   }
}

The jaxws-endpoint-config.xml descriptor is used to provide a custom endpoint configuration with the required server side configuration properties; in particular for this Username Token case that’s just a CXF configuration option for leaving the username token validation to the configured interceptors:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">
  <endpoint-config>
    <config-name>Custom WS-Security Endpoint</config-name>
    <property>
      <property-name>ws-security.validate.token</property-name>
      <property-value>false</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

In order for requiring a given JBoss security domain to be used to protect access to the endpoint (a POJO one in this case), we declare that in a jboss-web.xml descriptor (the JBossWS security domain is used):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
   <security-domain>java:/jaas/JBossWS</security-domain>
</jboss-web

Finally, the web.xml is as simple as usual:

<?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>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
</web-app>

The endpoint is packaged into a war archive, including the JAXWS classes generated by wsconsume:

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-samples-wsse-policy-username-jaas.war
     0 Thu Jun 16 18:50:48 CEST 2011 META-INF/
   155 Thu Jun 16 18:50:46 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/
   585 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/
   982 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/POJOEndpointAuthorizationInterceptor.class
   412 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceIface.class
  1398 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaas/ServiceImpl.class
     0 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/
   701 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMe.class
  1065 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/GreetMeResponse.class
   705 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHello.class
  1069 Thu Jun 16 18:50:48 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/samples/wsse/policy/jaxws/SayHelloResponse.class
   556 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jaxws-endpoint-config.xml
   241 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/jboss-web.xml
     0 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/
  3183 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService.wsdl
  1012 Thu Jun 16 18:50:44 CEST 2011 WEB-INF/wsdl/SecurityService_schema1.xsd
Important

If you’re deploying the endpoint archive to WildFly, remember to add a dependency to org.apache.ws.security and org.apache.cxf module (due to the @InInterceptor annotation) in the MANIFEST.MF file.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.1
Created-By: 17.0-b16 (Sun Microsystems Inc.)
Dependencies: org.apache.ws.security,org.apache.cxf
Client

Start by consuming the published WSDL contract using the wsconsume tool, then invoke the the endpoint as a standard JAX-WS one:

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ServiceIface proxy = (ServiceIface)service.getPort(ServiceIface.class);

((BindingProvider)proxy).getRequestContext().put(SecurityConstants.USERNAME, "kermit");
((BindingProvider)proxy).getRequestContext().put(SecurityConstants.CALLBACK_HANDLER,
      "org.jboss.test.ws.jaxws.samples.wsse.policy.jaas.UsernamePasswordCallback");

proxy.sayHello();

The UsernamePasswordCallback class is shown below and is responsible for setting the passwords on client side just before performing the invocations:

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

import java.io.IOException;
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 UsernamePasswordCallback implements CallbackHandler
{
   public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
   {
      WSPasswordCallback pc = (WSPasswordCallback)callbacks[0];
      if ("kermit".equals(pc.getIdentifier()))
         pc.setPassword("thefrog");
   }
}

If everything has been done properly, you should expect calls to sayHello() to fail when done with user "snoopy" and pass with user "kermit" (and credential "thefrog"); moreover, you should get an authorization error when trying to call greetMe() with user "kermit", as that does not have the "snoopies" role.

Secure transport

Another quite common use case is using WS-Security Username Token Profile over a secure transport (HTTPS). A scenario like this is implemented similarly to what’s described in the previous example, except for few differences explained below.

Here is an excerpt of a wsdl with a sample security policy for Username Token over HTTPS:

...

<binding name="SecurityServicePortBinding" type="tns:ServiceIface">
  <wsp:PolicyReference URI="#SecurityServiceBindingPolicy"/>
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
  <operation name="sayHello">
    <soap:operation soapAction=""/>
    <input>
      <soap:body use="literal"/>
    </input>
    <output>
      <soap:body use="literal"/>
    </output>
  </operation>
</binding>
<service name="SecurityService">
   <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="https://localhost:8443/jaxws-samples-wsse-policy-username"/>
   </port>
</service>

<wsp:Policy wsu:Id="SecurityServiceBindingPolicy">
   <wsp:ExactlyOne>
      <wsp:All>
         <foo:unknownPolicy xmlns:foo="http://cxf.apache.org/not/a/policy"/>
      </wsp:All>
      <wsp:All>
         <wsaws:UsingAddressing xmlns:wsaws="http://www.w3.org/2006/05/addressing/wsdl"/>
         <sp:TransportBinding>
            <wsp:Policy>
               <sp:TransportToken>
                  <wsp:Policy>
                     <sp:HttpsToken RequireClientCertificate="false"/>
                  </wsp:Policy>
               </sp:TransportToken>
               <sp:Layout>
                  <wsp:Policy>
                     <sp:Lax/>
                  </wsp:Policy>
               </sp:Layout>
               <sp:IncludeTimestamp/>
               <sp:AlgorithmSuite>
                  <wsp:Policy>
                     <sp:Basic128/>
                  </wsp:Policy>
               </sp:AlgorithmSuite>
            </wsp:Policy>
         </sp:TransportBinding>
         <sp:Wss10>
            <wsp:Policy>
               <sp:MustSupportRefKeyIdentifier/>
            </wsp:Policy>
         </sp:Wss10>
         <sp:SignedSupportingTokens>
            <wsp:Policy>
               <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                  <wsp:Policy>
                     <sp:WssUsernameToken10/>
                  </wsp:Policy>
               </sp:UsernameToken>
            </wsp:Policy>
         </sp:SignedSupportingTokens>
      </wsp:All>
   </wsp:ExactlyOne>
</wsp:Policy>

The endpoint needs to be available on HTTPS only, so we have a web.xml setting the transport-guarantee such as below:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   version="5.0" xmlns="https://jakarta.ee/xml/ns/jakartaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee http://java.sun.com/xml/ns/javaee/web-app_5_0.xsd">
   <servlet>
      <servlet-name>TestService</servlet-name>
      <servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.basic.ServiceImpl</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>TestService</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>

   <security-constraint>
    <web-resource-collection>
      <web-resource-name>TestService</web-resource-name>
      <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
  </security-constraint>
</web-app>
Secure conversation

Apache CXF supports WS-SecureConversation specification, which is about improving performance by allowing client and server to negotiate initial security keys to be used for later communication encryption/signature. This is done by having two policies in the wsdl contract, an outer one setting the security requirements to communicate with the endpoint and a bootstrap one, related to the communication for establishing the secure conversation keys. The client will be automatically sending an initial message to the server for negotiating the keys, then the communication to the endpoint takes place. As a consequence, Apache CXF needs a way to specify which WS-Security configuration properties are intended for the bootstrap policy and which are intended for the actual service policy. To accomplish this, properties intended for the bootstrap policy are appended with .sct .

...
((BindingProvider)proxy).getRequestContext().put("ws-security.signature.username.sct", "alice");
((BindingProvider)proxy).getRequestContext().put("ws-security.encryption.username.sct", "bob");
...
@WebService(
   ...
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.encryption.properties.sct", value = "bob.properties"),
      @EndpointProperty(key = "ws-security.signature.properties.sct", value = "bob.properties"),
      ...
      }
)
public class ServiceImpl implements ServiceIface {
   ...
}

5.13. WS-Trust and STS

5.13.1. WS-Trust overview

WS-Trust is a Web service specification that defines extensions to WS-Security. It is a general framework for implementing security in a distributed system. The standard is based on a centralized Security Token Service, STS, which is capable of authenticating clients and issuing tokens containing various kinds of authentication and authorization data. The specification describes a protocol used for issuance, exchange, and validation of security tokens, however the following specifications play an important role in the WS-Trust architecture: WS-SecurityPolicy 1.2 , SAML 2.0 , Username Token Profile , X.509 Token Profile , SAML Token Profile , and Kerberos Token Profile .

The WS-Trust extensions address the needs of applications that span multiple domains and requires the sharing of security keys by providing a standards based trusted third party web service (STS) to broker trust relationships between a Web service requester and a Web service provider. This architecture also alleviates the pain of service updates that require credential changes by providing a common location for this information. The STS is the common access point from which both the requester and provider retrieves and verifies security tokens.

There are three main components of the WS-Trust specification.

  • The Security Token Service (STS), a web service that issues, renews, and validates security tokens.

  • The message formats for security token requests and responses.

  • The mechanisms for key exchange

5.13.2. Security Token Service

The Security Token Service, STS, is the core of the WS-Trust specification. It is a standards based mechanism for authentication and authorization. The STS is an implementation of the WS-Trust specification’s protocol for issuing, exchanging, and validating security tokens, based on token format, namespace, or trust boundaries. The STS is a web service that acts as a trusted third party to broker trust relationships between a Web service requester and a Web service provider. It is a common access point trusted by both requester and provider to provide interoperable security tokens. It removes the need for a direct relationship between the two. Because the STS is a standards based mechanism for authentication, it helps ensure interoperability across realms and between different platforms.

The STS’s WSDL contract defines how other applications and processes interact with it. In particular the WSDL defines the WS-Trust and WS-Security policies that a requester must fulfill in order to successfully communicate with the STS’s endpoints. A web service requester consumes the STS’s WSDL and with the aid of an STSClient utility, generates a message request compliant with the stated security policies and submits it to the STS endpoint. The STS validates the request and returns an appropriate response.

5.13.3. Apache CXF support

Apache CXF is an open-source, fully featured Web services framework. The JBossWS open source project integrates the JBoss Web Services (JBossWS) stack with the Apache CXF project modules thus providing WS-Trust and other JAX-WS functionality in WildFly. This integration makes it easy to deploy CXF STS implementations, however WildFly can run any WS-Trust compliant STS. In addition the Apache CXF API provides a STSClient utility to facilitate web service requester communication with its STS.

Detailed information about the Apache CXF’s WS-Trust implementation can be found here .

5.13.4. A Basic WS-Trust Scenario

Here is an example of a basic WS-Trust scenario. It is comprised of a Web service requester (ws-requester), a Web service provider (ws-provider), and a Security Token Service (STS). The ws-provider requires a SAML 2.0 token issued from a designed STS to be presented by the ws-requester using asymmetric binding. These communication requirements are declared in the ws-provider’s WSDL. The STS requires ws-requester credentials be provided in a WSS UsernameToken format request using symmetric binding. The STS’s response is provided containing a SAML 2.0 token. These communication requirements are declared in the STS’s WSDL.

  1. A ws-requester contacts the ws-provider and consumes its WSDL. Upon finding the security token issuer requirement, it creates and configures a STSClient with the information it requires to generate a proper request.

  2. The STSClient contacts the STS and consumes its WSDL. The security policies are discovered. The STSClient creates and sends an authentication request, with appropriate credentials.

  3. The STS verifies the credentials.

  4. In response, the STS issues a security token that provides proof that the ws-requester has authenticated with the STS.

  5. The STClient presents a message with the security token to the ws-provider.

  6. The ws-provider verifies the token was issued by the STS, thus proving the ws-requester has successfully authenticated with the STS.

  7. The ws-provider executes the requested service and returns the results to the the ws-requester.

Web service provider

This section examines the crucial elements in providing endpoint security in the web service provider described in the basic WS-Trust scenario. The components that will be discussed are.

  • web service provider’s WSDL

  • web service provider’s Interface and Implementation classes.

  • ServerCallbackHandler class

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The web service provider is a contract-first endpoint. All the WS-trust and security policies for it are declared in the WSDL, SecurityService.wsdl. For this scenario a ws-requester is required to present a SAML 2.0 token issued from a designed STS. The address of the STS is provided in the WSDL. An asymmetric binding policy is used to encrypt and sign the SOAP body of messages that pass back and forth between ws-requester and ws-provider. X.509 certificates are use for the asymmetric binding. The rules for sharing the public and private keys in the SOAP request and response messages are declared. A detailed explanation of the security settings are provided in the comments in the listing below.

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" name="SecurityService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsaws="http://www.w3.org/2005/08/addressing"
        xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
        xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy" schemaLocation="SecurityService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="ServiceIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
  <!--
        The wsp:PolicyReference binds the security requirments on all the STS endpoints.
        The wsp:Policy wsu:Id="#AsymmetricSAML2Policy" element is defined later in this file.
  -->
  <binding name="SecurityServicePortBinding" type="tns:ServiceIface">
    <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
        <wsp:PolicyReference URI="#Input_Policy" />
      </input>
      <output>
        <soap:body use="literal"/>
        <wsp:PolicyReference URI="#Output_Policy" />
      </output>
    </operation>
  </binding>
  <service name="SecurityService">
    <port name="SecurityServicePort" binding="tns:SecurityServicePortBinding">
      <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust/SecurityService"/>
    </port>
  </service>
 
  <wsp:Policy wsu:Id="AsymmetricSAML2Policy">
        <wsp:ExactlyOne>
            <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->               
                <wsam:Addressing wsp:Optional="false">
                    <wsp:Policy />
                </wsam:Addressing>
  <!--
        The sp:AsymmetricBinding element indicates that security is provided
        at the SOAP layer. A public/private key combinations is required to
        protect the message.  The initiator will use it’s private key to sign
        the message and the recipient’s public key is used to encrypt the message.
        The recipient of the message will use it’s private key to decrypt it and
        initiator’s public key to verify the signature.
  -->              
                <sp:AsymmetricBinding>
                    <wsp:Policy>
  <!--
        The sp:InitiatorToken element specifies the elements required in
        generating the initiator request to the ws-provider's service.
  -->                              
                        <sp:InitiatorToken>
                            <wsp:Policy>
  <!--
        The sp:IssuedToken element asserts that a SAML 2.0 security token is
        expected from the STS using a public key type.  The
        sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
        attribute instructs the runtime to include the initiator's public key
        with every message sent to the recipient.
        
        The sp:RequestSecurityTokenTemplate element directs that all of the
        children of this element will be copied directly into the body of the
        RequestSecurityToken (RST) message that is sent to the STS when the
        initiator asks the STS to issue a token.
  -->
                                <sp:IssuedToken
                                    sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                                    <sp:RequestSecurityTokenTemplate>
                                        <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
                                        <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/PublicKey</t:KeyType>
                                    </sp:RequestSecurityTokenTemplate>
                                    <wsp:Policy>
                                        <sp:RequireInternalReference />
                                    </wsp:Policy>
  <!--
        The sp:Issuer element defines the STS's address and endpoint information
        This information is used by the STSClient.
  -->                                   
                                    <sp:Issuer>
                                        <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService</wsaws:Address>
                                        <wsaws:Metadata xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                                                        wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService?wsdl">
                                            <wsaw:ServiceName xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                                                            xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                                                            EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                                        </wsaws:Metadata>
                                    </sp:Issuer>
                                </sp:IssuedToken>
                            </wsp:Policy>
                        </sp:InitiatorToken>
  <!--
        The sp:RecipientToken element asserts the type of public/private key-pair
        expected from the recipient.  The
        sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
        attribute indicates that the initiator's public key will never be included
        in the reply messages.  

        The sp:WssX509V3Token10 element indicates that an X509 Version 3 token
        should be used in the message.
  -->                       
                        <sp:RecipientToken>
                            <wsp:Policy>
                                <sp:X509Token
                                    sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                                    <wsp:Policy>
                                        <sp:WssX509V3Token10 />
                                        <sp:RequireIssuerSerialReference />
                                    </wsp:Policy>
                                </sp:X509Token>
                            </wsp:Policy>
                        </sp:RecipientToken>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->                       
                        <sp:Layout>
                            <wsp:Policy>
                                <sp:Lax />
                            </wsp:Policy>
                        </sp:Layout>
                        <sp:IncludeTimestamp />
                        <sp:OnlySignEntireHeadersAndBody />
 <!--
     The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
     be used in performing cryptographic operations.
-->                      
                        <sp:AlgorithmSuite>
                            <wsp:Policy>
                                <sp:Basic256 />
                            </wsp:Policy>
                        </sp:AlgorithmSuite>
                    </wsp:Policy>
                </sp:AsymmetricBinding>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->               
                <sp:Wss11>
                    <wsp:Policy>
                        <sp:MustSupportRefIssuerSerial />
                        <sp:MustSupportRefThumbprint />
                        <sp:MustSupportRefEncryptedKey />
                    </wsp:Policy>
                </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.  
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->               
                <sp:Trust13>
                    <wsp:Policy>
                        <sp:MustSupportIssuedTokens />
                        <sp:RequireClientEntropy />
                        <sp:RequireServerEntropy />
                    </wsp:Policy>
                </sp:Trust13>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
    
    <wsp:Policy wsu:Id="Input_Policy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                    <sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
    
    <wsp:Policy wsu:Id="Output_Policy">
        <wsp:ExactlyOne>
            <wsp:All>
                <sp:EncryptedParts>
                    <sp:Body />
                </sp:EncryptedParts>
                <sp:SignedParts>
                    <sp:Body />
                    <sp:Header Name="To" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="From" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="FaultTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="ReplyTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="MessageID" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="RelatesTo" Namespace="http://www.w3.org/2005/08/addressing" />
                    <sp:Header Name="Action" Namespace="http://www.w3.org/2005/08/addressing" />
                </sp:SignedParts>
            </wsp:All>
        </wsp:ExactlyOne>
    </wsp:Policy>
</definitions>
Web service provider Interface

The web service provider interface class, ServiceIface, is a straight forward web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy"
)
public interface ServiceIface
{
   @WebMethod
   String sayHello();
}
Web service provider Implementation

The web service provider implementation class, ServiceImpl, is a simple POJO. It uses the standard WebService annotation to define the service endpoint. There are two Apache CXF annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. These annotations come from the Apache WSS4J project , which provides a Java implementation of the primary WS-Security standards for Web Services. These annotations are programmatically adding properties to the endpoint. With plain Apache CXF, these properties are often set via the <jaxws:properties> element on the <jaxws:endpoint> element in the Spring config; these annotations allow the properties to be configured in the code.

WSS4J uses the Crypto interface to get keys and certificates for encryption/decryption and for signature creation/verification. As is asserted by the WSDL, X509 keys and certificates are required for this service. The WSS4J configuration information being provided by ServiceImpl is for Crypto’s Merlin implementation. More information will be provided about this in the keystore section.

The first EndpointProperty statement in the listing is declaring the user’s name to use for the message signature. It is used as the alias name in the keystore to get the user’s cert and private key for signature. The next two EndpointProperty statements declares the Java properties file that contains the (Merlin) crypto configuration information. In this case both for signing and encrypting the messages. WSS4J reads this file and extra required information for message handling. The last EndpointProperty statement declares the ServerCallbackHandler implementation class. It is used to obtain the user’s password for the certificates in the keystore file.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;

import jakarta.jws.WebService;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;

@WebService
(
   portName = "SecurityServicePort",
   serviceName = "SecurityService",
   wsdlLocation = "WEB-INF/wsdl/SecurityService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface"
)
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myservicekey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "serviceKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServerCallbackHandler")
})
public class ServiceImpl implements ServiceIface
{
   public String sayHello()
   {
      return "WS-Trust Hello World!";
   }
}
ServerCallbackHandler

ServerCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. A certificates' password is not discoverable. The creator of the certificate must record the password he assigns and provide it when requested through the CallbackHandler. In this scenario skpass is the password for user myservicekey.

 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service;

import java.util.HashMap;
import java.util.Map;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

public class ServerCallbackHandler extends PasswordCallbackHandler
{

   public ServerCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myservicekey", "skpass");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File serviceKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWS and Apache CXF APIs provided in module org.jboss.ws.cxf.jbossws-cxf-client. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0  
Ant-Version: Apache Ant 1.8.2  
Created-By: 1.7.0_25-b15 (Oracle Corporation)  
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client
Security Token Service (STS)

This section examines the crucial elements in providing the Security Token Service functionality described in the basic WS-Trust scenario. The components that will be discussed are.

  • STS’s WSDL

  • STS’s implementation class.

  • STSCallbackHandler class

  • Crypto properties and keystore files

  • MANIFEST.MF

  • Server configuration files

STS WSDL

The STS is a contract-first endpoint. All the WS-trust and security policies for it are declared in the WSDL, ws-trust-1.4-service.wsdl. A symmetric binding policy is used to encrypt and sign the SOAP body of messages that pass back and forth between ws-requester and the STS. The ws-requester is required to authenticate itself by providing WSS UsernameToken credentials. The rules for sharing the public and private keys in the SOAP request and response messages are declared. A detailed explanation of the security settings is provided in the comments in the listing below.

 <?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
        targetNamespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:tns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:wstrust="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">

  <wsdl:types>
    <xs:schema elementFormDefault="qualified" targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>

      <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' />
      <xs:element name='RequestSecurityTokenResponse' type='wst:AbstractRequestSecurityTokenType' />

      <xs:complexType name='AbstractRequestSecurityTokenType' >
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional' />
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection' type='wst:RequestSecurityTokenCollectionType' />
      <xs:complexType name='RequestSecurityTokenCollectionType' >
        <xs:sequence>
          <xs:element name='RequestSecurityToken' type='wst:AbstractRequestSecurityTokenType' minOccurs='2' maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>

      <xs:element name='RequestSecurityTokenResponseCollection' type='wst:RequestSecurityTokenResponseCollectionType' />
      <xs:complexType name='RequestSecurityTokenResponseCollectionType' >
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1' maxOccurs='unbounded' />
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax' />
      </xs:complexType>

    </xs:schema>
  </wsdl:types>

  <!-- WS-Trust defines the following GEDs -->
  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken" />
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseMsg">
    <wsdl:part name="response"
            element="wst:RequestSecurityTokenResponse" />
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenCollectionMsg">
    <wsdl:part name="requestCollection"
            element="wst:RequestSecurityTokenCollection"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
            element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>

  <!-- This portType an example of a Requestor (or other) endpoint that
         Accepts SOAP-based challenges from a Security Token Service -->
  <wsdl:portType name="WSSecurityRequestor">
    <wsdl:operation name="Challenge">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>


  <!-- This portType is an example of an STS supporting full protocol -->
<!--
    The wsdl:portType and data types are XML elements defined by the
    WS_Trust specification.  The wsdl:portType defines the endpoints
    supported in the STS implementation.  This WSDL defines all operations
    that an STS implementation can support.
-->      
  <wsdl:portType name="STS">
    <wsdl:operation name="Cancel">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/CancelFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Issue">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal" message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/RenewFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/ValidateFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <wsdl:input wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KET" message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/KETFinal" message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <wsdl:input message="tns:RequestSecurityTokenCollectionMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an endpoint that accepts
         Unsolicited RequestSecurityTokenResponse messages -->
  <wsdl:portType name="SecurityTokenResponseService">
    <wsdl:operation name="RequestSecurityTokenResponse">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

<!--
    The wsp:PolicyReference binds the security requirments on all the STS endpoints.
    The wsp:Policy wsu:Id="UT_policy" element is later in this file.
-->
  <wsdl:binding name="UT_Binding" type="wstrust:STS">
    <wsp:PolicyReference URI="#UT_policy" />
      <soap:binding style="document"
          transport="http://schemas.xmlsoap.org/soap/http" />
      <wsdl:operation name="Issue">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue" />
          <wsdl:input>
              <wsp:PolicyReference
               URI="#Input_policy" />
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <wsp:PolicyReference
               URI="#Output_policy" />
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Validate">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate" />
          <wsdl:input>
              <wsp:PolicyReference
               URI="#Input_policy" />
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <wsp:PolicyReference
               URI="#Output_policy" />
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Cancel">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="Renew">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="KeyExchangeToken">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KeyExchangeToken" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
      <wsdl:operation name="RequestCollection">
          <soap:operation
              soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/RequestCollection" />
          <wsdl:input>
              <soap:body use="literal" />
          </wsdl:input>
          <wsdl:output>
              <soap:body use="literal" />
          </wsdl:output>
      </wsdl:operation>
  </wsdl:binding>
 
  <wsdl:service name="SecurityTokenService">
      <wsdl:port name="UT_Port" binding="tns:UT_Binding">
         <soap:address location="http://localhost:8080/SecurityTokenService/UT" />
      </wsdl:port>
  </wsdl:service>
 
  <wsp:Policy wsu:Id="UT_policy">
      <wsp:ExactlyOne>
         <wsp:All>
<!--
    The sp:UsingAddressing element, indicates that the endpoints of this
    web service conforms to the WS-Addressing specification.  More detail
    can be found here: [http://www.w3.org/TR/2006/CR-ws-addr-wsdl-20060529]
-->  
            <wsap10:UsingAddressing/>
<!--
    The sp:SymmetricBinding element indicates that security is provided
    at the SOAP layer and any initiator must authenticate itself by providing
    WSS UsernameToken credentials.
-->            
            <sp:SymmetricBinding
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
<!--
    In a symmetric binding, the keys used for encrypting and signing in both
    directions are derived from a single key, the one specified by the
    sp:ProtectionToken element.  The sp:X509Token sub-element declares this
    key to be a X.509 certificate and the
    IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"
    attribute adds the requirement that the token MUST NOT be included in
    any messages sent between the initiator and the recipient; rather, an
    external reference to the token should be used.  Lastly the WssX509V3Token10
    sub-element declares that the Username token presented by the initiator
    should be compliant with Web Services Security UsernameToken Profile
    1.0 specification. [ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf ]
-->                      
                  <sp:ProtectionToken>
                     <wsp:Policy>
                        <sp:X509Token
                           sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                           <wsp:Policy>
                              <sp:RequireDerivedKeys />
                              <sp:RequireThumbprintReference />
                              <sp:WssX509V3Token10 />
                           </wsp:Policy>
                        </sp:X509Token>
                     </wsp:Policy>
                  </sp:ProtectionToken>
<!--
    The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
    be used in performing cryptographic operations.
-->                  
                  <sp:AlgorithmSuite>
                     <wsp:Policy>
                        <sp:Basic256 />
                     </wsp:Policy>
                  </sp:AlgorithmSuite>
<!--
    The sp:Layout element,  indicates the layout rules to apply when adding
    items to the security header.  The sp:Lax sub-element indicates items
    are added to the security header in any order that conforms to
    WSS: SOAP Message Security.
-->                 
                  <sp:Layout>
                     <wsp:Policy>
                        <sp:Lax />
                     </wsp:Policy>
                  </sp:Layout>
                  <sp:IncludeTimestamp />
                  <sp:EncryptSignature />
                  <sp:OnlySignEntireHeadersAndBody />
               </wsp:Policy>
            </sp:SymmetricBinding>
<!--
    The sp:SignedSupportingTokens element declares that the security header
    of messages must contain a sp:UsernameToken and the token must be signed.  
    The attribute IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"
    on sp:UsernameToken indicates that the token MUST be included in all
    messages sent from initiator to the recipient and that the token MUST
    NOT be included in messages sent from the recipient to the initiator.  
    And finally the element sp:WssUsernameToken10 is a policy assertion
    indicating the Username token should be as defined in  Web Services
    Security UsernameToken Profile 1.0
-->            
            <sp:SignedSupportingTokens
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:UsernameToken
                     sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                     <wsp:Policy>
                        <sp:WssUsernameToken10 />
                     </wsp:Policy>
                  </sp:UsernameToken>
               </wsp:Policy>
            </sp:SignedSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->            
            <sp:Wss11
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportRefKeyIdentifier />
                  <sp:MustSupportRefIssuerSerial />
                  <sp:MustSupportRefThumbprint />
                  <sp:MustSupportRefEncryptedKey />
               </wsp:Policy>
            </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.  
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->            
            <sp:Trust13
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <wsp:Policy>
                  <sp:MustSupportIssuedTokens />
                  <sp:RequireClientEntropy />
                  <sp:RequireServerEntropy />
               </wsp:Policy>
            </sp:Trust13>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>
   
   <wsp:Policy wsu:Id="Input_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>
   
   <wsp:Policy wsu:Id="Output_policy">
      <wsp:ExactlyOne>
         <wsp:All>
            <sp:SignedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
               <sp:Header Name="To"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="From"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="FaultTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="ReplyTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="MessageID"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="RelatesTo"
                  Namespace="http://www.w3.org/2005/08/addressing" />
               <sp:Header Name="Action"
                  Namespace="http://www.w3.org/2005/08/addressing" />
            </sp:SignedParts>
            <sp:EncryptedParts
               xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
               <sp:Body />
            </sp:EncryptedParts>
         </wsp:All>
      </wsp:ExactlyOne>
   </wsp:Policy>

</wsdl:definitions>
STS Implementation

The Apache CXF’s STS, SecurityTokenServiceProvider, is a web service provider that is compliant with the protocols and functionality defined by the WS-Trust specification. It has a modular architecture. Many of its components are configurable or replaceable and there are many optional features that are enabled by implementing and configuring plug-ins. Users can customize their own STS by extending from SecurityTokenServiceProvider and overriding the default settings. Extensive information about the CXF’s STS configurable and pluggable components can be found here .

This STS implementation class, SimpleSTS, is a POJO that extends from SecurityTokenServiceProvider. Note that the class is defined with a WebServiceProvider annotation and not a WebService annotation. This annotation defines the service as a Provider-based endpoint, meaning it supports a more messaging-oriented approach to Web services. In particular, it signals that the exchanged messages will be XML documents of some type. SecurityTokenServiceProvider is an implementation of the jakarta.xml.ws.Provider interface. In comparison the WebService annotation defines a (service endpoint interface) SEI-based endpoint which supports message exchange via SOAP envelopes.

As was done in the ServiceImpl class, the WSS4J annotations EndpointProperties and EndpointProperty are providing endpoint configuration for the CXF runtime. This was previous described Web service provider Implementation .

The InInterceptors annotation is used to specify a JBossWS integration interceptor to be used for authenticating incoming requests; JAAS integration is used here for authentication, the username/passoword coming from the UsernameToken in the ws-requester message are used for authenticating the requester against a security domain on the application server hosting the STS deployment.

In this implementation we are customizing the operations of token issuance, token validation and their static properties.

StaticSTSProperties is used to set select properties for configuring resources in the STS. You may think this is a duplication of the settings made with the WSS4J annotations. The values are the same but the underlaying structures being set are different, thus this information must be declared in both places.

The setIssuer setting is important because it uniquely identifies the issuing STS. The issuer string is embedded in issued tokens and, when validating tokens, the STS checks the issuer string value. Consequently, it is important to use the issuer string in a consistent way, so that the STS can recognize the tokens that it has issued.

The setEndpoints call allows the declaration of a set of allowed token recipients by address. The addresses are specified as reg-ex patterns.

TokenIssueOperation and TokenValidateOperation have a modular structure. This allows custom behaviors to be injected into the processing of messages. In this case we are overriding the SecurityTokenServiceProvider’s default behavior and performing SAML token processing and validation. CXF provides an implementation of a SAMLTokenProvider and SAMLTokenValidator which we are using rather than writing our own.

Learn more about the SAMLTokenProvider here .

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust;
 
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
 
import jakarta.xml.ws.WebServiceProvider;
 
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;
 
@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.STSCallbackHandler"),
      //to let the JAAS integration deal with validation through the interceptor below
      @EndpointProperty(key = "ws-security.validate.token", value = "false")
        
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
   public SampleSTS() throws Exception
   {
      super();
 
      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignaturePropertiesFile("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");
 
      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
              "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
              "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
              "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService"
              ));
      services.add(service);
 
      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.setServices(services);
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      issueOperation.setStsProperties(props);
 
      TokenValidateOperation validateOperation = new TokenValidateOperation();
      validateOperation.getTokenValidators().add(new SAMLTokenValidator());
      validateOperation.setStsProperties(props);
 
      this.setIssueOperation(issueOperation);
      this.setValidateOperation(validateOperation);
   }
}
STSCallbackHandler

STSCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;

import java.util.HashMap;
import java.util.Map;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

public class STSCallbackHandler extends PasswordCallbackHandler
{
   public STSCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File stsKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
MANIFEST.MF

When deployed on WildFly, this application requires access to the JBossWS and Apache CXF APIs provided in module org.jboss.ws.cxf.jbossws-cxf-client. The org.jboss.ws.cxf.sts module is also needed to build the STS configuration in the SampleSTS constructor. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0  
Ant-Version: Apache Ant 1.8.2  
Created-By: 1.7.0_25-b15 (Oracle Corporation)  
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.jboss.ws.cxf.sts
Security Domain

The STS requires a JBoss security domain be configured. The jboss-web.xml descriptor declares a named security domain,"JBossWS-trust-sts" to be used by this service for authentication. This security domain requires two properties files and the addition of a security-domain declaration in the JBoss server configuration file.

For this scenario the domain needs to contain user alice , password clarinet , and role friend . See the listings below for jbossws-users.properties and jbossws-roles.properties. The following XML must be added to the JBoss security subsystem in the server configuration file. Replace " SOME_PATH " with appropriate information.

 <security-domain name="JBossWS-trust-sts">
  <authentication>
    <login-module code="UsersRoles" flag="required">
      <module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
      <module-option name="unauthenticatedIdentity" value="anonymous"/>
      <module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
    </login-module>
  </authentication>
</security-domain>

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" ">  
<jboss-web>  
  <security-domain>java:/jaas/JBossWS-trust-sts</security-domain>  
</jboss-web>

jbossws-users.properties

# A sample users.properties file for use with the UsersRolesLoginModule  
alice=clarinet

jbossws-roles.properties

# A sample roles.properties file for use with the UsersRolesLoginModule  
alice=friend
Tip
WS-MetadataExchange and interoperability

To achieve better interoperability, you might consider allowing the STS endpoint to reply to WS-MetadataExchange messages directed to the /mex URL sub-path (e.g. http://localhost:8080/jaxws-samples-wsse-policy-trust-sts/SecurityTokenService/mex ). This can be done by tweaking the url-pattern for the underlying endpoint servlet, for instance by adding a web.xml descriptor as follows to the deployment:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="5.0" xmlns="https://jakarta.ee/xml/ns/jakartaee""
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"> <servlet>
<servlet-name>TestSecurityTokenService</servlet-name>
<servlet-class>org.jboss.test.ws.jaxws.samples.wsse.policy.trust.SampleSTS</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>TestSecurityTokenService</servlet-name>
<url-pattern>/SecurityTokenService/*</url-pattern> </servlet-mapping>
</web-app>

At the time of writing some webservices implementations (including Metro ) assume the /mex URL as the default choice for directing WS-MetadataExchange requests to and use that to retrieve STS wsdl contracts.

Web service requester

This section examines the crucial elements in calling a web service that implements endpoint security as described in the basic WS-Trust scenario. The components that will be discussed are.

  • web service requestor’s implementation

  • ClientCallbackHandler

  • Crypto properties and keystore files

Web service requester Implementation

The ws-requester, the client, uses standard procedures for creating a reference to the web service in the first four line. To address the endpoint security requirements, the web service’s "Request Context" is configured with the information needed in message generation. The STSClient that communicates with the STS is configured with similar values. Note the key strings ending with a ".it" suffix. This suffix flags these settings as belonging to the STSClient. The internal CXF code assigns this information to the STSClient that is auto-generated for this service call.

There is an alternate method of setting up the STSCLient. The user may provide their own instance of the STSClient. The CXF code will use this object and not auto-generate one. This is used in the ActAs and OnBehalfOf examples. When providing the STSClient in this way, the user must provide a org.apache.cxf.Bus for it and the configuration keys must not have the ".it" suffix.

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");  
URL wsdlURL = new URL(serviceURL + "?wsdl");  
Service service = Service.create(wsdlURL, serviceName);  
ServiceIface proxy = (ServiceIface) service.getPort(ServiceIface.class);  
 
// set the security related configuration information for the service "request"  
Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();  
ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());  
ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));  
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));  
ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");  
ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");  
 
 
//-- Configuration settings that will be transfered to the STSClient  
// "alice" is the name provided for the WSS Username. Her password will  
// be retreived from the ClientCallbackHander by the STSClient.  
ctx.put(SecurityConstants.USERNAME + ".it", "alice");  
ctx.put(SecurityConstants.CALLBACK_HANDLER + ".it", new ClientCallbackHandler());  
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES + ".it",
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));  
ctx.put(SecurityConstants.ENCRYPT_USERNAME + ".it", "mystskey");  
// alias name in the keystore to get the user's public key to send to the STS  
ctx.put(SecurityConstants.STS_TOKEN_USERNAME + ".it", "myclientkey");  
// Crypto property configuration to use for the STS  
ctx.put(SecurityConstants.STS_TOKEN_PROPERTIES + ".it",
   Thread.currentThread().getContextClassLoader().getResource(
   "META-INF/clientKeystore.properties"));  
// write out an X509Certificate structure in UseKey/KeyInfo  
ctx.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO + ".it", "true");  
// Setting indicates the  STSclient should not try using the WS-MetadataExchange  
// call using STS EPR WSA address when the endpoint contract does not contain  
// WS-MetadataExchange info.  
ctx.put("ws-security.sts.disable-wsmex-call-using-epr-address", "true");  
   
proxy.sayHello();
ClientCallbackHandler

ClientCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. Note that "alice" and her password have been provided here. This information is not in the (JKS) keystore but provided in the WildFly security domain. It was declared in file jbossws-users.properties.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;  
 
import java.io.IOException;  
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 ClientCallbackHandler implements CallbackHandler {  
 
    public void handle(Callback[] callbacks) throws IOException,  
            UnsupportedCallbackException {  
        for (int i = 0; i < callbacks.length; i++) {  
            if (callbacks[i] instanceof WSPasswordCallback) {  
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];  
                if ("myclientkey".equals(pc.getIdentifier())) {  
                    pc.setPassword("ckpass");  
                    break;  
                } else if ("alice".equals(pc.getIdentifier())) {  
                    pc.setPassword("clarinet");  
                    break;  
                }  
            }  
        }  
    }  
}
Requester Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File clientKeystore.properties contains this information.

File clientstore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=cspass
org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/clientstore.jks

5.13.5. ActAs WS-Trust Scenario

The ActAs feature is used in scenarios that require composite delegation. It is commonly used in multi-tiered systems where an application calls a service on behalf of a logged in user or a service calls another service on behalf of the original caller.

ActAs is nothing more than a new sub-element in the RequestSecurityToken (RST). It provides additional information about the original caller when a token is negotiated with the STS. The ActAs element usually takes the form of a token with identity claims such as name, role, and authorization code, for the client to access the service.

The ActAs scenario is an extension of A Basic WS-Trust Scenario. In this example the ActAs service calls the ws-service on behalf of a user. There are only a couple of additions to the basic scenario’s code. An ActAs web service provider and callback handler have been added. The ActAs web services' WSDL imposes the same security policies as the ws-provider. UsernameTokenCallbackHandler is new. It is a utility that generates the content for the ActAs element. And lastly there are a couple of code additions in the STS to support the ActAs request.

Web service provider

This section examines the web service elements from the basic WS-Trust scenario that have been changed to address the needs of the ActAs example. The components are

  • ActAs web service provider’s WSDL

  • ActAs web service provider’s Interface and Implementation classes.

  • ActAsCallbackHandler class

  • UsernameTokenCallbackHandler

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The ActAs web service provider’s WSDL is a clone of the ws-provider’s WSDL. The wsp:Policy section is the same. There are changes to the service endpoint, targetNamespace, portType, binding name, and service.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy" name="ActAsService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
                    schemaLocation="ActAsService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="ActAsServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="ActAsServicePortBinding" type="tns:ActAsServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="ActAsService">
        <port name="ActAsServicePort" binding="tns:ActAsServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-actas/ActAsService"/>
        </port>
    </service>

</definitions>
Web Service Interface

The web service provider interface class, ActAsServiceIface, is a simple web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy"
)
public interface ActAsServiceIface
{
   @WebMethod
   String sayHello();
}
Web Service Implementation

The web service provider implementation class, ActAsServiceImpl, is a POJO. It uses the standard WebService annotation to define the service endpoint and two Apache WSS4J annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. The WSS4J configuration information provided is for WSS4J’s Crypto Merlin implementation.

ActAsServiceImpl is calling ServiceImpl acting on behalf of the user. Method setupService performs the requisite configuration setup.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;

import jakarta.jws.WebService;
import javax.xml.namespace.QName;
import jakarta.xml.ws.BindingProvider;
import jakarta.xml.ws.Service;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

@WebService
(
   portName = "ActAsServicePort",
   serviceName = "ActAsService",
   wsdlLocation = "WEB-INF/wsdl/ActAsService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsServiceIface"
)

@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas.ActAsCallbackHandler")
})

public class ActAsServiceImpl implements ActAsServiceIface
{
   public String sayHello() {
      try {
         ServiceIface proxy = setupService();
         return "ActAs " + proxy.sayHello();
      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }

   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();

      try {
         BusFactory.setThreadDefaultBus(bus);

         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);

         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new ActAsCallbackHandler());

         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "alice");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource("actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

         ctx.put(SecurityConstants.STS_CLIENT, stsClient);

      } finally {
         bus.shutdown(true);
      }

      return proxy;
   }

}
ActAsCallbackHandler

ActAsCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. This class has been revised to return the passwords for this service, myactaskey and the "actas" user, alice.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.actas;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;

public class ActAsCallbackHandler extends PasswordCallbackHandler {

   public ActAsCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
UsernameTokenCallbackHandler

The ActAs and OnBeholdOf sub-elements of the RequestSecurityToken are required to be defined as WSSE Username Tokens. This utility generates the properly formated element.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.message.Message;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.delegation.DelegationCallback;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.token.UsernameToken;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;
import java.util.Map;

/**
* A utility to provide the 3 different input parameter types for jaxws property
* "ws-security.sts.token.act-as" and "ws-security.sts.token.on-behalf-of".
* This implementation obtains a username and password via the jaxws property
* "ws-security.username" and "ws-security.password" respectively, as defined
* in SecurityConstants.  It creates a wss UsernameToken to be used as the
* delegation token.
*/

public class UsernameTokenCallbackHandler implements CallbackHandler {

   public void handle(Callback[] callbacks)
      throws IOException, UnsupportedCallbackException {
      for (int i = 0; i < callbacks.length; i++) {
         if (callbacks[i] instanceof DelegationCallback) {
            DelegationCallback callback = (DelegationCallback) callbacks[i];
            Message message = callback.getCurrentMessage();

            String username =
               (String)message.getContextualProperty(SecurityConstants.USERNAME);
            String password =
               (String)message.getContextualProperty(SecurityConstants.PASSWORD);
            if (username != null) {
               Node contentNode = message.getContent(Node.class);
               Document doc = null;
               if (contentNode != null) {
                  doc = contentNode.getOwnerDocument();
               } else {
                  doc = DOMUtils.createDocument();
               }
               UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
               callback.setToken(usernameToken.getElement());
            }
         } else {
            throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
         }
      }
   }

   /**
    * Provide UsernameToken as a string.
    * @param ctx
    * @return
    */
   public String getUsernameTokenString(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      String result = null;
      String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }

   /**
    *
    * @param username
    * @param password
    * @return
    */
   public String getUsernameTokenString(String username, String password){
      Document doc = DOMUtils.createDocument();
      String result = null;
      if (username != null) {
         UsernameToken usernameToken = createWSSEUsernameToken(username,password, doc);
         result = toString(usernameToken.getElement().getFirstChild().getParentNode());
      }
      return result;
   }

   /**
    * Provide UsernameToken as a DOM Element.
    * @param ctx
    * @return
    */
   public Element getUsernameTokenElement(Map<String, Object> ctx){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
         String username = (String)ctx.get(SecurityConstants.USERNAME);
      String password = (String)ctx.get(SecurityConstants.PASSWORD);
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }

   /**
    *
    * @param username
    * @param password
    * @return
    */
   public Element getUsernameTokenElement(String username, String password){
      Document doc = DOMUtils.createDocument();
      Element result = null;
      UsernameToken usernameToken = null;
      if (username != null) {
         usernameToken = createWSSEUsernameToken(username,password, doc);
         result = usernameToken.getElement();
      }
      return result;
   }

   private UsernameToken createWSSEUsernameToken(String username, String password, Document doc) {

      UsernameToken usernameToken = new UsernameToken(true, doc,
         (password == null)? null: WSConstants.PASSWORD_TEXT);
      usernameToken.setName(username);
      usernameToken.addWSUNamespace();
      usernameToken.addWSSENamespace();
      usernameToken.setID("id-" + username);

      if (password != null){
         usernameToken.setPassword(password);
      }

      return usernameToken;
   }


   private String toString(Node node) {
      String str = null;

      if (node != null) {
         DOMImplementationLS lsImpl = (DOMImplementationLS)
            node.getOwnerDocument().getImplementation().getFeature("LS", "3.0");
         LSSerializer serializer = lsImpl.createLSSerializer();
         serializer.getDomConfig().setParameter("xml-declaration", false); //by default its true, so set it to false to get String without xml-declaration
         str = serializer.writeToString(node);
      }
      return str;
   }

}
Crypto properties and keystore files

The ActAs service must provide its own credentials. The requisite properties file, actasKeystore.properties, and keystore, actasstore.jks, were created.

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=aapass
org.apache.ws.security.crypto.merlin.keystore.alias=myactaskey
org.apache.ws.security.crypto.merlin.keystore.file=actasstore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWS and Apache CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client. The org.jboss.ws.cxf.sts module is also needed in handling the ActAs and OnBehalfOf extensions. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.2
Created-By: 1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client, org.jboss.ws.cxf.sts
Security Token Service

This section examines the STS elements from the basic WS-Trust scenario that have been changed to address the needs of the ActAs example. The components are.

  • STS’s implementation class.

  • STSCallbackHandler class

STS Implementation class

The initial description of SampleSTS can be found [_actas_ws_trust_scenario]

The declaration of the set of allowed token recipients by address has been extended to accept ActAs addresses and OnBehalfOf addresses. The addresses are specified as reg-ex patterns.

The TokenIssueOperation requires class, UsernameTokenValidator be provided in order to validate the contents of the OnBehalfOf claims and class, UsernameTokenDelegationHandler to be provided in order to process the token delegation request of the ActAs on OnBehalfOf user.

 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import jakarta.xml.ws.WebServiceProvider;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.interceptor.InInterceptors;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.operation.TokenValidateOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.delegation.UsernameTokenDelegationHandler;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.sts.token.validator.SAMLTokenValidator;
import org.apache.cxf.sts.token.validator.UsernameTokenValidator;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/ws-trust-1.4-service.wsdl")
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts.STSCallbackHandler"),
      @EndpointProperty(key = "ws-security.validate.token", value = "false") //to let the JAAS integration deal with validation through the interceptor below
})
@InInterceptors(interceptors = {"org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"})
public class SampleSTS extends SecurityTokenServiceProvider
{
   public SampleSTS() throws Exception
   {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSCallbackHandler.class.getName());
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust/SecurityService",

         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-actas/ActAsService",

         "http://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService",
         "http://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService"
      ));
      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.setServices(services);
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      // required for OnBehalfOf
      issueOperation.getTokenValidators().add(new UsernameTokenValidator());
      // added for OnBehalfOf and ActAs
      issueOperation.getDelegationHandlers().add(new UsernameTokenDelegationHandler());
      issueOperation.setStsProperties(props);

      TokenValidateOperation validateOperation = new TokenValidateOperation();
      validateOperation.getTokenValidators().add(new SAMLTokenValidator());
      validateOperation.setStsProperties(props);

      this.setIssueOperation(issueOperation);
      this.setValidateOperation(validateOperation);
   }
}
STSCallbackHandler

The user, alice, and corresponding password was required to be added for the ActAs example.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.sts;

import java.util.HashMap;
import java.util.Map;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

public class STSCallbackHandler extends PasswordCallbackHandler
{
   public STSCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
Web service requester

This section examines the ws-requester elements from the basic WS-Trust scenario that have been changed to address the needs of the ActAs example. The component is

  • ActAs web service requester implementation class

Web service requester Implementation

The ActAs ws-requester, the client, uses standard procedures for creating a reference to the web service in the first four lines. To address the endpoint security requirements, the web service’s "Request Context" is configured via the BindingProvider. Information needed in the message generation is provided through it. The ActAs user, myactaskey, is declared in this section and UsernameTokenCallbackHandler is used to provide the contents of the ActAs element to the STSClient. In this example a STSClient object is created and provided to the proxy’s request context. The alternative is to provide keys tagged with the ".it" suffix as was done in the Basic Scenario client . The use of ActAs is configured through the props map using the SecurityConstants.STS_TOKEN_ACT_AS key. The alternative is to use the STSClient.setActAs method.

 final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/actaswssecuritypolicy", "ActAsService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
ActAsServiceIface proxy = (ActAsServiceIface) service.getPort(ActAsServiceIface.class);

Bus bus = BusFactory.newInstance().createBus();
try {
    BusFactory.setThreadDefaultBus(bus);

    Map<String, Object> ctx = proxy.getRequestContext();

    ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myactaskey");
    ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");

    // Generate the ActAs element contents and pass to the STSClient as a string
    UsernameTokenCallbackHandler ch = new UsernameTokenCallbackHandler();
    String str = ch.getUsernameTokenString("alice","clarinet");
    ctx.put(SecurityConstants.STS_TOKEN_ACT_AS, str);

    STSClient stsClient = new STSClient(bus);
    Map<String, Object> props = stsClient.getProperties();
    props.put(SecurityConstants.USERNAME, "bob");
    props.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    props.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
    props.put(SecurityConstants.STS_TOKEN_USERNAME, "myclientkey");
    props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

    ctx.put(SecurityConstants.STS_CLIENT, stsClient);
} finally {
    bus.shutdown(true);
}
proxy.sayHello();

5.13.6. OnBehalfOf WS-Trust Scenario

The OnBehalfOf feature is used in scenarios that use the proxy pattern. In such scenarios, the client cannot access the STS directly, instead it communicates through a proxy gateway. The proxy gateway authenticates the caller and puts information about the caller into the OnBehalfOf element of the RequestSecurityToken (RST) sent to the real STS for processing. The resulting token contains only claims related to the client of the proxy, making the proxy completely transparent to the receiver of the issued token.

OnBehalfOf is nothing more than a new sub-element in the RST. It provides additional information about the original caller when a token is negotiated with the STS. The OnBehalfOf element usually takes the form of a token with identity claims such as name, role, and authorization code, for the client to access the service.

The OnBehalfOf scenario is an extension of A Basic WS-Trust Scenario . In this example the OnBehalfOf service calls the ws-service on behalf of a user. There are only a couple of additions to the basic scenario’s code. An OnBehalfOf web service provider and callback handler have been added. The OnBehalfOf web services' WSDL imposes the same security policies as the ws-provider. UsernameTokenCallbackHandler is a utility shared with ActAs. It generates the content for the OnBehalfOf element. Lastly there are code additions in the STS that both OnBehalfOf and ActAs share in common.

Web service provider

This section examines the web service elements from the basic WS-Trust scenario that have been changed to address the needs of the OnBehalfOf example. The components are.

  • web service provider’s WSDL

  • web service provider’s Interface and Implementation classes.

  • OnBehalfOfCallbackHandler class

Web service provider WSDL

The OnBehalfOf web service provider’s WSDL is a clone of the ws-provider’s WSDL. The wsp:Policy section is the same. There are changes to the service endpoint, targetNamespace, portType, binding name, and service.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy" name="OnBehalfOfService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
    <types>
        <xsd:schema>
            <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
                  schemaLocation="OnBehalfOfService_schema1.xsd"/>
        </xsd:schema>
    </types>
    <message name="sayHello">
        <part name="parameters" element="tns:sayHello"/>
    </message>
    <message name="sayHelloResponse">
        <part name="parameters" element="tns:sayHelloResponse"/>
    </message>
    <portType name="OnBehalfOfServiceIface">
        <operation name="sayHello">
            <input message="tns:sayHello"/>
            <output message="tns:sayHelloResponse"/>
        </operation>
    </portType>
    <binding name="OnBehalfOfServicePortBinding" type="tns:OnBehalfOfServiceIface">
        <wsp:PolicyReference URI="#AsymmetricSAML2Policy" />
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <operation name="sayHello">
            <soap:operation soapAction=""/>
            <input>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Input_Policy" />
            </input>
            <output>
                <soap:body use="literal"/>
                <wsp:PolicyReference URI="#Output_Policy" />
            </output>
        </operation>
    </binding>
    <service name="OnBehalfOfService">
        <port name="OnBehalfOfServicePort" binding="tns:OnBehalfOfServicePortBinding">
            <soap:address location="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-onbehalfof/OnBehalfOfService"/>
        </port>
    </service>
</definitions>
Web Service Interface

The web service provider interface class, OnBehalfOfServiceIface, is a simple web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy"
)
public interface OnBehalfOfServiceIface
{
   @WebMethod
   String sayHello();
}
Web Service Implementation

The web service provider implementation class, OnBehalfOfServiceImpl, is a POJO. It uses the standard WebService annotation to define the service endpoint and two Apache WSS4J annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. The WSS4J configuration information provided is for WSS4J’s Crypto Merlin implementation.

OnBehalfOfServiceImpl is calling the ServiceImpl acting on behalf of the user. Method setupService performs the requisite configuration setup.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.ws.security.SecurityConstants;
import org.apache.cxf.ws.security.trust.STSClient;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.service.ServiceIface;
import org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared.WSTrustAppUtils;

import jakarta.jws.WebService;
import javax.xml.namespace.QName;
import jakarta.xml.ws.BindingProvider;
import jakarta.xml.ws.Service;
import java.net.*;
import java.util.Map;

@WebService
(
   portName = "OnBehalfOfServicePort",
   serviceName = "OnBehalfOfService",
   wsdlLocation = "WEB-INF/wsdl/OnBehalfOfService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof.OnBehalfOfServiceIface"
)

@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "myactaskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value =  "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.encryption.properties", value = "actasKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof.OnBehalfOfCallbackHandler")
})

public class OnBehalfOfServiceImpl implements OnBehalfOfServiceIface
{
   public String sayHello() {
      try {

         ServiceIface proxy = setupService();
         return "OnBehalfOf " + proxy.sayHello();

      } catch (MalformedURLException e) {
         e.printStackTrace();
      }
      return null;
   }

   /**
    *
    * @return
    * @throws MalformedURLException
    */
   private  ServiceIface setupService()throws MalformedURLException {
      ServiceIface proxy = null;
      Bus bus = BusFactory.newInstance().createBus();

      try {
         BusFactory.setThreadDefaultBus(bus);

         final String serviceURL = "http://" + WSTrustAppUtils.getServerHost() + ":8080/jaxws-samples-wsse-policy-trust/SecurityService";
         final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wssecuritypolicy", "SecurityService");
         final URL wsdlURL = new URL(serviceURL + "?wsdl");
         Service service = Service.create(wsdlURL, serviceName);
         proxy = (ServiceIface) service.getPort(ServiceIface.class);

         Map<String, Object> ctx = ((BindingProvider) proxy).getRequestContext();
         ctx.put(SecurityConstants.CALLBACK_HANDLER, new OnBehalfOfCallbackHandler());

         ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "actasKeystore.properties" ));
         ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myactaskey" );
         ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "../../META-INF/clientKeystore.properties" ));
         ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

         STSClient stsClient = new STSClient(bus);
         Map<String, Object> props = stsClient.getProperties();
         props.put(SecurityConstants.USERNAME, "bob");
         props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
         props.put(SecurityConstants.STS_TOKEN_USERNAME, "myactaskey" );
         props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
            Thread.currentThread().getContextClassLoader().getResource(
            "actasKeystore.properties" ));
         props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

         ctx.put(SecurityConstants.STS_CLIENT, stsClient);

      } finally {
         bus.shutdown(true);
      }

      return proxy;
   }

}
OnBehalfOfCallbackHandler

OnBehalfOfCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. This class has been revised to return the passwords for this service, myactaskey and the "OnBehalfOf" user, alice.

 package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.onbehalfof;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;
import java.util.HashMap;
import java.util.Map;

public class OnBehalfOfCallbackHandler extends PasswordCallbackHandler {

   public OnBehalfOfCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("myactaskey", "aspass");
      passwords.put("alice", "clarinet");
      passwords.put("bob", "trombone");
      return passwords;
   }

}
Web service requester

This section examines the ws-requester elements from the basic WS-Trust scenario that have been changed to address the needs of the OnBehalfOf example. The component is

  • OnBehalfOf web service requester implementation class

Web service requester Implementation

The OnBehalfOf ws-requester, the client, uses standard procedures for creating a reference to the web service in the first four lines. To address the endpoint security requirements, the web service’s "Request Context" is configured via the BindingProvider. Information needed in the message generation is provided through it. The OnBehalfOf user, alice, is declared in this section and the callbackHandler, UsernameTokenCallbackHandler is provided to the STSClient for generation of the contents for the OnBehalfOf message element. In this example a STSClient object is created and provided to the proxy’s request context. The alternative is to provide keys tagged with the ".it" suffix as was done in the Basic Scenario client. The use of OnBehalfOf is configured by the method call stsClient.setOnBehalfOf. The alternative is to use the key SecurityConstants.STS_TOKEN_ON_BEHALF_OF and a value in the props map.

final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/onbehalfofwssecuritypolicy", "OnBehalfOfService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
OnBehalfOfServiceI face proxy = (OnBehalfOfServiceIface) service.getPort(OnBehalfOfServiceIface.class);


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

    BusFactory.setThreadDefaultBus(bus);

    Map<String, Object> ctx = proxy.getRequestContext();

    ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myactaskey");
    ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");

    // user and password OnBehalfOf user
    // UsernameTokenCallbackHandler will extract this information when called
    ctx.put(SecurityConstants.USERNAME,"alice");
    ctx.put(SecurityConstants.PASSWORD, "clarinet");

    STSClient stsClient = new STSClient(bus);

    // Providing the STSClient the mechanism to create the claims contents for OnBehalfOf
    stsClient.setOnBehalfOf(new UsernameTokenCallbackHandler());

    Map<String, Object> props = stsClient.getProperties();
    props.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
    props.put(SecurityConstants.ENCRYPT_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.ENCRYPT_USERNAME, "mystskey");
    props.put(SecurityConstants.STS_TOKEN_USERNAME, "myclientkey");
    props.put(SecurityConstants.STS_TOKEN_PROPERTIES,
        Thread.currentThread().getContextClassLoader().getResource(
        "META-INF/clientKeystore.properties"));
    props.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO, "true");

    ctx.put(SecurityConstants.STS_CLIENT, stsClient);

} finally {
    bus.shutdown(true);
}
proxy.sayHello();

5.13.7. SAML Bearer Assertion Scenario

WS-Trust deals with managing software security tokens. A SAML assertion is a type of security token. In the SAML Bearer scenario, the service provider automatically trusts that the incoming SOAP request came from the subject defined in the SAML token after the service verifies the tokens signature.

Implementation of this scenario has the following requirements.

  • SAML tokens with a Bearer subject confirmation method must be protected so the token can not be snooped. In most cases, a bearer token combined with HTTPS is sufficient to prevent "a man in the middle" getting possession of the token. This means a security policy that uses a sp:TransportBinding and sp:HttpsToken.

  • A bearer token has no encryption or signing keys associated with it, therefore a sp:IssuedToken of bearer keyType should be used with a sp:SupportingToken or a sp:SignedSupportingTokens.

Web service Provider

This section examines the web service elements for the SAML Bearer scenario. The components are

  • Bearer web service provider’s WSDL

  • SSL configuration

  • Bearer web service provider’s Interface and Implementation classes.

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The web service provider is a contract-first endpoint. All the WS-trust and security policies for it are declared in WSDL, BearerService.wsdl. For this scenario a ws-requester is required to present a SAML 2.0 Bearer token issued from a designed STS. The address of the STS is provided in the WSDL. HTTPS, a TransportBinding and HttpsToken policy are used to protect the SOAP body of messages that pass back and forth between ws-requester and ws-provider. A detailed explanation of the security settings are provided in the comments in the listing below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
             name="BearerService"
             xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:wsp="http://www.w3.org/ns/ws-policy"
             xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
             xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
             xmlns:wsaws="http://www.w3.org/2005/08/addressing"
             xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
             xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
             xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">

  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
                  schemaLocation="BearerService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="BearerIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>

<!--
        The wsp:PolicyReference binds the security requirments on all the endpoints.
        The wsp:Policy wsu:Id="#TransportSAML2BearerPolicy" element is defined later in this file.
-->
  <binding name="BearerServicePortBinding" type="tns:BearerIface">
    <wsp:PolicyReference URI="#TransportSAML2BearerPolicy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>

<!--
  The soap:address has been defined to use JBoss's https port, 8443.  This is
  set in conjunction with the sp:TransportBinding policy for https.
-->
  <service name="BearerService">
    <port name="BearerServicePort" binding="tns:BearerServicePortBinding">
      <soap:address location="https://@jboss.bind.address@:8443/jaxws-samples-wsse-policy-trust-bearer/BearerService"/>
    </port>
  </service>


  <wsp:Policy wsu:Id="TransportSAML2BearerPolicy">
    <wsp:ExactlyOne>
      <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->
        <wsam:Addressing wsp:Optional="false">
          <wsp:Policy />
        </wsam:Addressing>

<!--
  The sp:TransportBinding element indicates that security is provided by the
  message exchange transport medium, https.  WS-Security policy specification
  defines the sp:HttpsToken for use in exchanging messages transmitted over HTTPS.
-->
        <sp:TransportBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:TransportToken>
              <wsp:Policy>
                <sp:HttpsToken>
                  <wsp:Policy/>
                </sp:HttpsToken>
              </wsp:Policy>
            </sp:TransportToken>
<!--
     The sp:AlgorithmSuite element, requires the TripleDes algorithm suite
     be used in performing cryptographic operations.
-->
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:TripleDes />
              </wsp:Policy>
            </sp:AlgorithmSuite>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax />
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp />
          </wsp:Policy>
        </sp:TransportBinding>

<!--
  The sp:SignedSupportingTokens element causes the supporting tokens
  to be signed using the primary token that is used to sign the message.
-->
        <sp:SignedSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
<!--
  The sp:IssuedToken element asserts that a SAML 2.0 security token of type
  Bearer is expected from the STS.  The
  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
  attribute instructs the runtime to include the initiator's public key
  with every message sent to the recipient.

  The sp:RequestSecurityTokenTemplate element directs that all of the
  children of this element will be copied directly into the body of the
  RequestSecurityToken (RST) message that is sent to the STS when the
  initiator asks the STS to issue a token.
-->
            <sp:IssuedToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <sp:RequestSecurityTokenTemplate>
                <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
                <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</t:KeyType>
              </sp:RequestSecurityTokenTemplate>
              <wsp:Policy>
                <sp:RequireInternalReference />
              </wsp:Policy>
<!--
  The sp:Issuer element defines the STS's address and endpoint information
  This information is used by the STSClient.
-->
              <sp:Issuer>
                <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-bearer/SecurityTokenService</wsaws:Address>
                <wsaws:Metadata
                  xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                  wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-bearer/SecurityTokenService?wsdl">
                  <wsaw:ServiceName
                    xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                    xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                    EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                </wsaws:Metadata>
              </sp:Issuer>

            </sp:IssuedToken>
          </wsp:Policy>
        </sp:SignedSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->
        <sp:Wss11>
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial />
            <sp:MustSupportRefThumbprint />
            <sp:MustSupportRefEncryptedKey />
          </wsp:Policy>
        </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->
        <sp:Trust13>
          <wsp:Policy>
            <sp:MustSupportIssuedTokens />
            <sp:RequireClientEntropy />
            <sp:RequireServerEntropy />
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</definitions>
SSL configuration

This web service is using https, therefore the JBoss server must be configured to provide SSL support in the Web subsystem. There are 2 components to SSL configuration.

  • create a certificate keystore

  • declare an SSL connector in the Web subsystem of the JBoss server configuration file.

Follow the directions this section in the Configure SSL/TLS .

Here is an example of an SSL connector declaration.

<subsystem xmlns="urn:jboss:domain:web:1.4" default-virtual-server="default-host" native="false">
  .....
  <connector name="jbws-https-connector" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true" enabled="true">
    <ssl key-alias="tomcat" password="changeit" certificate-key-file="/myJbossHome/security/test.keystore" verify-client="false"/>
  </connector>
  ...
Web service Interface

The web service provider interface class, BearerIface, is a simple straight forward web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy"
)
public interface BearerIface
{
   @WebMethod
   String sayHello();
}
Web service Implementation

The web service provider implementation class, BearerImpl, is a POJO. It uses the standard WebService annotation to define the service endpoint. There are two Apache CXF annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. These annotations come from the Apache WSS4J project , which provides a Java implementation of the primary WS-Security standards for Web Services. These annotations are programmatically adding properties to the endpoint. With plain Apache CXF, these properties are often set via the <jaxws:properties> element on the <jaxws:endpoint> element in the Spring config; these annotations allow the properties to be configured in the code.

WSS4J uses the Crypto interface to get keys and certificates for signature creation/verification, as is asserted by the WSDL for this service. The WSS4J configuration information being provided by BearerImpl is for Crypto’s Merlin implementation. More information will be provided about this in the keystore section.

Because the web service provider automatically trusts that the incoming SOAP request came from the subject defined in the SAML token there is no need for a Crypto callbackHandler class or a signature username, unlike in prior examples, however in order to verify the message signature, the Java properties file that contains the (Merlin) crypto configuration information is still required.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;

import jakarta.jws.WebService;

@WebService
(
   portName = "BearerServicePort",
   serviceName = "BearerService",
   wsdlLocation = "WEB-INF/wsdl/BearerService.wsdl",
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy",
   endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.bearer.BearerIface"
)
@EndpointProperties(value = {
   @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties")
})
public class BearerImpl implements BearerIface
{
   public String sayHello()
   {
      return "Bearer WS-Trust Hello World!";
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File serviceKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWs and CXF APIs provided in module org.jboss.ws.cxf.jbossws-cxf-client. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0  
Ant-Version: Apache Ant 1.8.2  
Created-By: 1.7.0_25-b15 (Oracle Corporation)  
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client
Bearer Security Token Service

This section examines the crucial elements in providing the Security Token Service functionality for providing a SAML Bearer token. The components that will be discussed are.

  • Security Domain

  • STS’s WSDL

  • STS’s implementation class

  • STSBearerCallbackHandler

  • Crypto properties and keystore files

  • MANIFEST.MF

Security Domain

The STS requires a JBoss security domain be configured. The jboss-web.xml descriptor declares a named security domain,"JBossWS-trust-sts" to be used by this service for authentication. This security domain requires two properties files and the addition of a security-domain declaration in the JBoss server configuration file.

For this scenario the domain needs to contain user alice , password clarinet , and role friend . See the listings below for jbossws-users.properties and jbossws-roles.properties. The following XML must be added to the JBoss security subsystem in the server configuration file. Replace " SOME_PATH " with appropriate information.

<security-domain name="JBossWS-trust-sts">
  <authentication>
    <login-module code="UsersRoles" flag="required">
      <module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
      <module-option name="unauthenticatedIdentity" value="anonymous"/>
      <module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
    </login-module>
  </authentication>
</security-domain>

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" ">  
<jboss-web>  
  <security-domain>java:/jaas/JBossWS-trust-sts</security-domain>  
</jboss-web>

jbossws-users.properties

# A sample users.properties file for use with the UsersRolesLoginModule  
alice=clarinet

jbossws-roles.properties

# A sample roles.properties file for use with the UsersRolesLoginModule  
alice=friend
STS’s WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:tns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wstrust="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:wsp="http://www.w3.org/ns/ws-policy"
  xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">

  <wsdl:types>
    <xs:schema elementFormDefault="qualified"
               targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>

      <xs:element name='RequestSecurityToken'
                  type='wst:AbstractRequestSecurityTokenType'/>
      <xs:element name='RequestSecurityTokenResponse'
                  type='wst:AbstractRequestSecurityTokenType'/>

      <xs:complexType name='AbstractRequestSecurityTokenType'>
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0'
                  maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional'/>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection'
                  type='wst:RequestSecurityTokenCollectionType'/>
      <xs:complexType name='RequestSecurityTokenCollectionType'>
        <xs:sequence>
          <xs:element name='RequestSecurityToken'
                      type='wst:AbstractRequestSecurityTokenType' minOccurs='2'
                      maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>

      <xs:element name='RequestSecurityTokenResponseCollection'
                  type='wst:RequestSecurityTokenResponseCollectionType'/>
      <xs:complexType name='RequestSecurityTokenResponseCollectionType'>
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1'
                      maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>

    </xs:schema>
  </wsdl:types>

  <!-- WS-Trust defines the following GEDs -->
  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseMsg">
    <wsdl:part name="response"
               element="wst:RequestSecurityTokenResponse"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenCollectionMsg">
    <wsdl:part name="requestCollection"
               element="wst:RequestSecurityTokenCollection"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
               element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>

  <!-- This portType an example of a Requestor (or other) endpoint that
  Accepts SOAP-based challenges from a Security Token Service -->
  <wsdl:portType name="WSSecurityRequestor">
    <wsdl:operation name="Challenge">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an STS supporting full protocol -->
  <!--
      The wsdl:portType and data types are XML elements defined by the
      WS_Trust specification.  The wsdl:portType defines the endpoints
      supported in the STS implementation.  This WSDL defines all operations
      that an STS implementation can support.
  -->
  <wsdl:portType name="STS">
    <wsdl:operation name="Cancel">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/CancelFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Issue">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal"
        message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/RenewFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/ValidateFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KET"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/KETFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <wsdl:input message="tns:RequestSecurityTokenCollectionMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an endpoint that accepts
  Unsolicited RequestSecurityTokenResponse messages -->
  <wsdl:portType name="SecurityTokenResponseService">
    <wsdl:operation name="RequestSecurityTokenResponse">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!--
      The wsp:PolicyReference binds the security requirments on all the STS endpoints.
      The wsp:Policy wsu:Id="UT_policy" element is later in this file.
  -->
  <wsdl:binding name="UT_Binding" type="wstrust:STS">
    <wsp:PolicyReference URI="#UT_policy"/>
    <soap:binding style="document"
                  transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Issue">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Cancel">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KeyExchangeToken"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/RequestCollection"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="SecurityTokenService">
    <wsdl:port name="UT_Port" binding="tns:UT_Binding">
      <soap:address location="http://localhost:8080/SecurityTokenService/UT"/>
    </wsdl:port>
  </wsdl:service>


  <wsp:Policy wsu:Id="UT_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <!--
            The sp:UsingAddressing element, indicates that the endpoints of this
            web service conforms to the WS-Addressing specification.  More detail
            can be found here: [http://www.w3.org/TR/2006/CR-ws-addr-wsdl-20060529]
        -->
        <wsap10:UsingAddressing/>
        <!--
            The sp:SymmetricBinding element indicates that security is provided
            at the SOAP layer and any initiator must authenticate itself by providing
            WSS UsernameToken credentials.
        -->
        <sp:SymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <!--
                In a symmetric binding, the keys used for encrypting and signing in both
                directions are derived from a single key, the one specified by the
                sp:ProtectionToken element.  The sp:X509Token sub-element declares this
                key to be a X.509 certificate and the
                IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"
                attribute adds the requirement that the token MUST NOT be included in
                any messages sent between the initiator and the recipient; rather, an
                external reference to the token should be used.  Lastly the WssX509V3Token10
                sub-element declares that the Username token presented by the initiator
                should be compliant with Web Services Security UsernameToken Profile
                1.0 specification. [ http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf ]
            -->
            <sp:ProtectionToken>
              <wsp:Policy>
                <sp:X509Token
                  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                  <wsp:Policy>
                    <sp:RequireDerivedKeys/>
                    <sp:RequireThumbprintReference/>
                    <sp:WssX509V3Token10/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:ProtectionToken>
            <!--
                The sp:AlgorithmSuite element, requires the Basic256 algorithm suite
                be used in performing cryptographic operations.
            -->
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:Basic256/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <!--
                The sp:Layout element,  indicates the layout rules to apply when adding
                items to the security header.  The sp:Lax sub-element indicates items
                are added to the security header in any order that conforms to
                WSS: SOAP Message Security.
            -->
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:EncryptSignature/>
            <sp:OnlySignEntireHeadersAndBody/>
          </wsp:Policy>
        </sp:SymmetricBinding>

        <!--
            The sp:SignedSupportingTokens element declares that the security header
            of messages must contain a sp:UsernameToken and the token must be signed.
            The attribute IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"
            on sp:UsernameToken indicates that the token MUST be included in all
            messages sent from initiator to the recipient and that the token MUST
            NOT be included in messages sent from the recipient to the initiator.
            And finally the element sp:WssUsernameToken10 is a policy assertion
            indicating the Username token should be as defined in  Web Services
            Security UsernameToken Profile 1.0
        -->
        <sp:SignedSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:UsernameToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <wsp:Policy>
                <sp:WssUsernameToken10/>
              </wsp:Policy>
            </sp:UsernameToken>
          </wsp:Policy>
        </sp:SignedSupportingTokens>
        <!--
            The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
            to be supported by the STS.  These particular elements generally refer
            to how keys are referenced within the SOAP envelope.  These are normally
            handled by CXF.
        -->
        <sp:Wss11
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportRefKeyIdentifier/>
            <sp:MustSupportRefIssuerSerial/>
            <sp:MustSupportRefThumbprint/>
            <sp:MustSupportRefEncryptedKey/>
          </wsp:Policy>
        </sp:Wss11>
        <!--
            The sp:Trust13 element declares controls for WS-Trust 1.3 options.
            They are policy assertions related to exchanges specifically with
            client and server challenges and entropy behaviors.  Again these are
            normally handled by CXF.
        -->
        <sp:Trust13
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportIssuedTokens/>
            <sp:RequireClientEntropy/>
            <sp:RequireServerEntropy/>
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Input_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Output_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</wsdl:definitions>
STS’s implementation class

The Apache CXF’s STS, SecurityTokenServiceProvider, is a web service provider that is compliant with the protocols and functionality defined by the WS-Trust specification. It has a modular architecture. Many of its components are configurable or replaceable and there are many optional features that are enabled by implementing and configuring plug-ins. Users can customize their own STS by extending from SecurityTokenServiceProvider and overriding the default settings. Extensive information about the CXF’s STS configurable and pluggable components can be found here .

This STS implementation class, SampleSTSBearer, is a POJO that extends from SecurityTokenServiceProvider. Note that the class is defined with a WebServiceProvider annotation and not a WebService annotation. This annotation defines the service as a Provider-based endpoint, meaning it supports a more messaging-oriented approach to Web services. In particular, it signals that the exchanged messages will be XML documents of some type. SecurityTokenServiceProvider is an implementation of the jakarta.xml.ws.Provider interface. In comparison the WebService annotation defines a (service endpoint interface) SEI-based endpoint which supports message exchange via SOAP envelopes.

As was done in the BearerImpl class, the WSS4J annotations EndpointProperties and EndpointProperty are providing endpoint configuration for the CXF runtime. The first EndpointProperty statement in the listing is declaring the user’s name to use for the message signature. It is used as the alias name in the keystore to get the user’s cert and private key for signature. The next two EndpointProperty statements declares the Java properties file that contains the (Merlin) crypto configuration information. In this case both for signing and encrypting the messages. WSS4J reads this file and extra required information for message handling. The last EndpointProperty statement declares the STSBearerCallbackHandler implementation class. It is used to obtain the user’s password for the certificates in the keystore file.

In this implementation we are customizing the operations of token issuance, token validation and their static properties.

StaticSTSProperties is used to set select properties for configuring resources in the STS. You may think this is a duplication of the settings made with the WSS4J annotations. The values are the same but the underlying structures being set are different, thus this information must be declared in both places.

The setIssuer setting is important because it uniquely identifies the issuing STS. The issuer string is embedded in issued tokens and, when validating tokens, the STS checks the issuer string value. Consequently, it is important to use the issuer string in a consistent way, so that the STS can recognize the tokens that it has issued.

The setEndpoints call allows the declaration of a set of allowed token recipients by address. The addresses are specified as reg-ex patterns.

TokenIssueOperation has a modular structure. This allows custom behaviors to be injected into the processing of messages. In this case we are overriding the SecurityTokenServiceProvider’s default behavior and performing SAML token processing. CXF provides an implementation of a SAMLTokenProvider which we are using rather than writing our own.

Learn more about the SAMLTokenProvider here .

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

import jakarta.xml.ws.WebServiceProvider;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

@WebServiceProvider(serviceName = "SecurityTokenService",
      portName = "UT_Port",
      targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
      wsdlLocation = "WEB-INF/wsdl/bearer-ws-trust-1.4-service.wsdl")
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
      @EndpointProperty(key = "ws-security.signature.username", value = "mystskey"),
      @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
      @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer.STSBearerCallbackHandler")
})
public class SampleSTSBearer extends SecurityTokenServiceProvider
{

   public SampleSTSBearer() throws Exception
   {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSBearerCallbackHandler.class.getName());
      props.setEncryptionCryptoProperties("stsKeystore.properties");
      props.setEncryptionUsername("myservicekey");
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "https://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService",
         "https://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService",
         "https://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-bearer/BearerService"
      ));
      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      issueOperation.setServices(services);
      issueOperation.setStsProperties(props);
      this.setIssueOperation(issueOperation);
   }
}
STSBearerCallbackHandler

STSBearerCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsbearer;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

import java.util.HashMap;
import java.util.Map;

public class STSBearerCallbackHandler extends PasswordCallbackHandler
{
   public STSBearerCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File stsKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
MANIFEST.MF

When deployed on WildFly, this application requires access to the JBossWS and Apache CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client. The org.jboss.ws.cxf.sts module is also needed to build the STS configuration in the SampleSTS constructor. The dependency statement directs the server to provide them at deployment.

Manifest-Version: 1.0  
Ant-Version: Apache Ant 1.8.2  
Created-By: 1.7.0_25-b15 (Oracle Corporation)  
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.jboss.ws.cxf.sts
Web service requester

This section examines the crucial elements in calling a web service that implements endpoint security as described in the SAML Bearer scenario. The components that will be discussed are.

  • Web service requester’s implementation

  • ClientCallbackHandler

  • Crypto properties and keystore files

Web service requester Implementation

The ws-requester, the client, uses standard procedures for creating a reference to the web service. To address the endpoint security requirements, the web service’s "Request Context" is configured with the information needed in message generation. The STSClient that communicates with the STS is configured with similar values. Note the key strings ending with a ".it" suffix. This suffix flags these settings as belonging to the STSClient. The internal CXF code assigns this information to the STSClient that is auto-generated for this service call.

There is an alternate method of setting up the STSCLient. The user may provide their own instance of the STSClient. The CXF code will use this object and not auto-generate one. When providing the STSClient in this way, the user must provide a org.apache.cxf.Bus for it and the configuration keys must not have the ".it" suffix. This is used in the ActAs and OnBehalfOf examples.

  String serviceURL = "https://" + getServerHost() + ":8443/jaxws-samples-wsse-policy-trust-bearer/BearerService";

  final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/bearerwssecuritypolicy", "BearerService");
  Service service = Service.create(new URL(serviceURL + "?wsdl"), serviceName);
  BearerIface proxy = (BearerIface) service.getPort(BearerIface.class);

  Map<String, Object> ctx = ((BindingProvider)proxy).getRequestContext();

  // set the security related configuration information for the service "request"
  ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
  ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
    Thread.currentThread().getContextClassLoader().getResource(
    "META-INF/clientKeystore.properties"));
  ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
    Thread.currentThread().getContextClassLoader().getResource(
    "META-INF/clientKeystore.properties"));
  ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");
  ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

  //-- Configuration settings that will be transfered to the STSClient
  // "alice" is the name provided for the WSS Username. Her password will
  // be retreived from the ClientCallbackHander by the STSClient.
  ctx.put(SecurityConstants.USERNAME + ".it", "alice");
  ctx.put(SecurityConstants.CALLBACK_HANDLER + ".it", new ClientCallbackHandler());
  ctx.put(SecurityConstants.ENCRYPT_PROPERTIES + ".it",
    Thread.currentThread().getContextClassLoader().getResource(
    "META-INF/clientKeystore.properties"));
  ctx.put(SecurityConstants.ENCRYPT_USERNAME + ".it", "mystskey");
  ctx.put(SecurityConstants.STS_TOKEN_USERNAME + ".it", "myclientkey");
  ctx.put(SecurityConstants.STS_TOKEN_PROPERTIES + ".it",
    Thread.currentThread().getContextClassLoader().getResource(
    "META-INF/clientKeystore.properties"));
  ctx.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO + ".it", "true");

  proxy.sayHello();
ClientCallbackHandler

ClientCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the username to use for the message signature. Note that "alice" and her password have been provided here. This information is not in the (JKS) keystore but provided in the WildFly security domain. It was declared in file jbossws-users.properties.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import java.io.IOException;
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 ClientCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                if ("myclientkey".equals(pc.getIdentifier())) {
                    pc.setPassword("ckpass");
                    break;
                } else if ("alice".equals(pc.getIdentifier())) {
                    pc.setPassword("clarinet");
                    break;
                } else if ("bob".equals(pc.getIdentifier())) {
                    pc.setPassword("trombone");
                    break;
                } else if ("myservicekey".equals(pc.getIdentifier())) {  // rls test  added for bearer test
                   pc.setPassword("skpass");
                   break;
                }
            }
        }
    }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File clientKeystore.properties contains this information.

File clientstore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=cspass
org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/clientstore.jks

5.13.8. SAML Holder-Of-Key Assertion Scenario

WS-Trust deals with managing software security tokens. A SAML assertion is a type of security token. In the Holder-Of-Key method, the STS creates a SAML token containing the client’s public key and signs the SAML token with its private key. The client includes the SAML token and signs the outgoing soap envelope to the web service with its private key. The web service validates the SOAP message and the SAML token.

Implementation of this scenario has the following requirements.

  • SAML tokens with a Holder-Of-Key subject confirmation method must be protected so the token can not be snooped. In most cases, a Holder-Of-Key token combined with HTTPS is sufficient to prevent "a man in the middle" getting possession of the token. This means a security policy that uses a sp:TransportBinding and sp:HttpsToken.

  • A Holder-Of-Key token has no encryption or signing keys associated with it, therefore a sp:IssuedToken of SymmetricKey or PublicKey keyType should be used with a sp:SignedEndorsingSupportingTokens.

Web service Provider

This section examines the web service elements for the SAML Holder-Of-Key scenario. The components are

  • Web service provider’s WSDL

  • SSL configuration

  • Web service provider’s Interface and Implementation classes.

  • Crypto properties and keystore files

  • MANIFEST.MF

Web service provider WSDL

The web service provider is a contract-first endpoint. All the WS-trust and security policies for it are declared in the WSDL, HolderOfKeyService.wsdl. For this scenario a ws-requester is required to present a SAML 2.0 token of SymmetricKey keyType, issued from a designed STS. The address of the STS is provided in the WSDL. A transport binding policy is used. The token is declared to be signed and endorsed, sp:SignedEndorsingSupportingTokens. A detailed explanation of the security settings are provided in the comments in the listing below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions targetNamespace="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
             name="HolderOfKeyService"
        xmlns:tns="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
        xmlns="http://schemas.xmlsoap.org/wsdl/"
        xmlns:wsp="http://www.w3.org/ns/ws-policy"
        xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
    xmlns:wsaws="http://www.w3.org/2005/08/addressing"
    xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
    xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"
    xmlns:t="http://docs.oasis-open.org/ws-sx/ws-trust/200512">

  <types>
    <xsd:schema>
      <xsd:import namespace="http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
                  schemaLocation="HolderOfKeyService_schema1.xsd"/>
    </xsd:schema>
  </types>
  <message name="sayHello">
    <part name="parameters" element="tns:sayHello"/>
  </message>
  <message name="sayHelloResponse">
    <part name="parameters" element="tns:sayHelloResponse"/>
  </message>
  <portType name="HolderOfKeyIface">
    <operation name="sayHello">
      <input message="tns:sayHello"/>
      <output message="tns:sayHelloResponse"/>
    </operation>
  </portType>
<!--
        The wsp:PolicyReference binds the security requirments on all the endpoints.
        The wsp:Policy wsu:Id="#TransportSAML2HolderOfKeyPolicy" element is defined later in this file.
-->
  <binding name="HolderOfKeyServicePortBinding" type="tns:HolderOfKeyIface">
    <wsp:PolicyReference URI="#TransportSAML2HolderOfKeyPolicy" />
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
    <operation name="sayHello">
      <soap:operation soapAction=""/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
<!--
  The soap:address has been defined to use JBoss's https port, 8443.  This is
  set in conjunction with the sp:TransportBinding policy for https.
-->
  <service name="HolderOfKeyService">
    <port name="HolderOfKeyServicePort" binding="tns:HolderOfKeyServicePortBinding">
      <soap:address location="https://@jboss.bind.address@:8443/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService"/>
    </port>
  </service>


  <wsp:Policy wsu:Id="TransportSAML2HolderOfKeyPolicy">
    <wsp:ExactlyOne>
      <wsp:All>
  <!--
        The wsam:Addressing element, indicates that the endpoints of this
        web service MUST conform to the WS-Addressing specification.  The
        attribute wsp:Optional="false" enforces this assertion.
  -->
        <wsam:Addressing wsp:Optional="false">
          <wsp:Policy />
        </wsam:Addressing>
<!--
  The sp:TransportBinding element indicates that security is provided by the
  message exchange transport medium, https.  WS-Security policy specification
  defines the sp:HttpsToken for use in exchanging messages transmitted over HTTPS.
-->
          <sp:TransportBinding
            xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
            <wsp:Policy>
              <sp:TransportToken>
                <wsp:Policy>
                  <sp:HttpsToken>
                    <wsp:Policy/>
                  </sp:HttpsToken>
                </wsp:Policy>
              </sp:TransportToken>
<!--
     The sp:AlgorithmSuite element, requires the TripleDes algorithm suite
     be used in performing cryptographic operations.
-->
              <sp:AlgorithmSuite>
                <wsp:Policy>
                  <sp:TripleDes />
                </wsp:Policy>
              </sp:AlgorithmSuite>
<!--
     The sp:Layout element,  indicates the layout rules to apply when adding
     items to the security header.  The sp:Lax sub-element indicates items
     are added to the security header in any order that conforms to
     WSS: SOAP Message Security.
-->
              <sp:Layout>
                <wsp:Policy>
                  <sp:Lax />
                </wsp:Policy>
              </sp:Layout>
              <sp:IncludeTimestamp />
            </wsp:Policy>
          </sp:TransportBinding>

<!--
  The sp:SignedEndorsingSupportingTokens, when transport level security level is
  used there will be no message signature and the signature generated by the
  supporting token will sign the Timestamp.
-->
        <sp:SignedEndorsingSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
<!--
  The sp:IssuedToken element asserts that a SAML 2.0 security token of type
  Bearer is expected from the STS.  The
  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
  attribute instructs the runtime to include the initiator's public key
  with every message sent to the recipient.

  The sp:RequestSecurityTokenTemplate element directs that all of the
  children of this element will be copied directly into the body of the
  RequestSecurityToken (RST) message that is sent to the STS when the
  initiator asks the STS to issue a token.
-->
            <sp:IssuedToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <sp:RequestSecurityTokenTemplate>
                <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
 <!--
   KeyType of "SymmetricKey", the client must prove to the WS service that it
   possesses a particular symmetric session key.
 -->
                <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey</t:KeyType>
              </sp:RequestSecurityTokenTemplate>
              <wsp:Policy>
                <sp:RequireInternalReference />
              </wsp:Policy>
<!--
  The sp:Issuer element defines the STS's address and endpoint information
  This information is used by the STSClient.
-->
              <sp:Issuer>
                <wsaws:Address>http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-holderofkey/SecurityTokenService</wsaws:Address>
                <wsaws:Metadata
                  xmlns:wsdli="http://www.w3.org/2006/01/wsdl-instance"
                  wsdli:wsdlLocation="http://@jboss.bind.address@:8080/jaxws-samples-wsse-policy-trust-sts-holderofkey/SecurityTokenService?wsdl">
                  <wsaw:ServiceName
                    xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl"
                    xmlns:stsns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
                    EndpointName="UT_Port">stsns:SecurityTokenService</wsaw:ServiceName>
                </wsaws:Metadata>
              </sp:Issuer>

            </sp:IssuedToken>
          </wsp:Policy>
        </sp:SignedEndorsingSupportingTokens>
<!--
    The sp:Wss11 element declares WSS: SOAP Message Security 1.1 options
    to be supported by the STS.  These particular elements generally refer
    to how keys are referenced within the SOAP envelope.  These are normally
    handled by CXF.
-->
        <sp:Wss11>
          <wsp:Policy>
            <sp:MustSupportRefIssuerSerial />
            <sp:MustSupportRefThumbprint />
            <sp:MustSupportRefEncryptedKey />
          </wsp:Policy>
        </sp:Wss11>
<!--
    The sp:Trust13 element declares controls for WS-Trust 1.3 options.
    They are policy assertions related to exchanges specifically with
    client and server challenges and entropy behaviors.  Again these are
    normally handled by CXF.
-->
        <sp:Trust13>
          <wsp:Policy>
            <sp:MustSupportIssuedTokens />
            <sp:RequireClientEntropy />
            <sp:RequireServerEntropy />
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</definitions>
SSL configuration

This web service is using https, therefore the JBoss server must be configured to provide SSL support in the Web subsystem. There are 2 components to SSL configuration.

  • create a certificate keystore

  • declare an SSL connector in the Web subsystem of the JBoss server configuration file.

Follow the directions in the section Configure SSL/TLS .

Here is an example of an SSL connector declaration.

<subsystem xmlns="urn:jboss:domain:web:1.4" default-virtual-server="default-host" native="false">
.....
  <connector name="jbws-https-connector" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true" enabled="true">
    <ssl key-alias="tomcat" password="changeit" certificate-key-file="/myJbossHome/security/test.keystore" verify-client="false"/>
  </connector>
...
Web service Interface

The web service provider interface class, HolderOfKeyIface, is a simple straight forward web service definition.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
(
   targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy"
)
public interface HolderOfKeyIface {
   @WebMethod
   String sayHello();
}
Web service Implementation

The web service provider implementation class, HolderOfKeyImpl, is a POJO. It uses the standard WebService annotation to define the service endpoint. There are two Apache CXF annotations, EndpointProperties and EndpointProperty used for configuring the endpoint for the CXF runtime. These annotations come from the Apache WSS4J project , which provides a Java implementation of the primary WS-Security standards for Web Services. These annotations are programmatically adding properties to the endpoint. With plain Apache CXF, these properties are often set via the <jaxws:properties> element on the <jaxws:endpoint> element in the Spring config; these annotations allow the properties to be configured in the code.

WSS4J uses the Crypto interface to get keys and certificates for signature creation/verification, as is asserted by the WSDL for this service. The WSS4J configuration information being provided by HolderOfKeyImpl is for Crypto’s Merlin implementation. More information will be provided about this in the keystore section.

The first EndpointProperty statement in the listing disables ensurance of compliance with the Basic Security Profile 1.1. The next EndpointProperty statements declares the Java properties file that contains the (Merlin) crypto configuration information. The last EndpointProperty statement declares the STSHolderOfKeyCallbackHandler implementation class. It is used to obtain the user’s password for the certificates in the keystore file.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;

import jakarta.jws.WebService;

@WebService
   (
      portName = "HolderOfKeyServicePort",
      serviceName = "HolderOfKeyService",
      wsdlLocation = "WEB-INF/wsdl/HolderOfKeyService.wsdl",
      targetNamespace = "http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy",
      endpointInterface = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey.HolderOfKeyIface"
   )
@EndpointProperties(value = {
   @EndpointProperty(key = "ws-security.is-bsp-compliant", value = "false"),
   @EndpointProperty(key = "ws-security.signature.properties", value = "serviceKeystore.properties"),
   @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.holderofkey.HolderOfKeyCallbackHandler")
})
public class HolderOfKeyImpl implements HolderOfKeyIface
{
   public String sayHello()
   {
      return "Holder-Of-Key WS-Trust Hello World!";
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File serviceKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=sspass
org.apache.ws.security.crypto.merlin.keystore.alias=myservicekey
org.apache.ws.security.crypto.merlin.keystore.file=servicestore.jks
MANIFEST.MF

When deployed on WildFly this application requires access to the JBossWs and CXF APIs provided in module org.jboss.ws.cxf.jbossws-cxf-client. The dependency statement directs the server to provide them at deployment.

Manifest-Version:1.0
Ant-Version: Apache Ant1.8.2
Created-By:1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client
Security Token Service

This section examines the crucial elements in providing the Security Token Service functionality for providing a SAML Holder-Of-Key token. The components that will be discussed are.

  • Security Domain

  • STS’s WSDL

  • STS’s implementation class

  • STSBearerCallbackHandler

  • Crypto properties and keystore files

  • MANIFEST.MF

Security Domain

The STS requires a JBoss security domain be configured. The jboss-web.xml descriptor declares a named security domain,"JBossWS-trust-sts" to be used by this service for authentication. This security domain requires two properties files and the addition of a security-domain declaration in the JBoss server configuration file.

For this scenario the domain needs to contain user alice , password clarinet , and role friend . See the listings below for jbossws-users.properties and jbossws-roles.properties. In addition the following XML must be added to the JBoss security subsystem in the server configuration file. Replace " SOME_PATH " with appropriate information.

<security-domain name="JBossWS-trust-sts">
  <authentication>
   <login-module code="UsersRoles" flag="required">
     <module-option name="usersProperties" value="/SOME_PATH/jbossws-users.properties"/>
     <module-option name="unauthenticatedIdentity" value="anonymous"/>
     <module-option name="rolesProperties" value="/SOME_PATH/jbossws-roles.properties"/>
   </login-module>
  </authentication>
</security-domain>

jboss-web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC"-//JBoss//DTD Web Application 2.4//EN" ">
<jboss-web>
  <security-domain>java:/jaas/JBossWS-trust-sts</security-domain>
</jboss-web>

jbossws-users.properties

# A sample users.properties filefor use with the UsersRolesLoginModule
alice=clarinet

 

jbossws-roles.properties

# A sample roles.properties filefor use with the UsersRolesLoginModule
alice=friend
STS’s WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
  targetNamespace="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:tns="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wstrust="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:wsap10="http://www.w3.org/2006/05/addressing/wsdl"
  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
  xmlns:wsp="http://www.w3.org/ns/ws-policy"
  xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata">

  <wsdl:types>
    <xs:schema elementFormDefault="qualified"
               targetNamespace='http://docs.oasis-open.org/ws-sx/ws-trust/200512'>

      <xs:element name='RequestSecurityToken'
                  type='wst:AbstractRequestSecurityTokenType'/>
      <xs:element name='RequestSecurityTokenResponse'
                  type='wst:AbstractRequestSecurityTokenType'/>

      <xs:complexType name='AbstractRequestSecurityTokenType'>
        <xs:sequence>
          <xs:any namespace='##any' processContents='lax' minOccurs='0'
                  maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:attribute name='Context' type='xs:anyURI' use='optional'/>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>
      <xs:element name='RequestSecurityTokenCollection'
                  type='wst:RequestSecurityTokenCollectionType'/>
      <xs:complexType name='RequestSecurityTokenCollectionType'>
        <xs:sequence>
          <xs:element name='RequestSecurityToken'
                      type='wst:AbstractRequestSecurityTokenType' minOccurs='2'
                      maxOccurs='unbounded'/>
        </xs:sequence>
      </xs:complexType>

      <xs:element name='RequestSecurityTokenResponseCollection'
                  type='wst:RequestSecurityTokenResponseCollectionType'/>
      <xs:complexType name='RequestSecurityTokenResponseCollectionType'>
        <xs:sequence>
          <xs:element ref='wst:RequestSecurityTokenResponse' minOccurs='1'
                      maxOccurs='unbounded'/>
        </xs:sequence>
        <xs:anyAttribute namespace='##other' processContents='lax'/>
      </xs:complexType>

    </xs:schema>
  </wsdl:types>

  <!-- WS-Trust defines the following GEDs -->
  <wsdl:message name="RequestSecurityTokenMsg">
    <wsdl:part name="request" element="wst:RequestSecurityToken"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseMsg">
    <wsdl:part name="response"
               element="wst:RequestSecurityTokenResponse"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenCollectionMsg">
    <wsdl:part name="requestCollection"
               element="wst:RequestSecurityTokenCollection"/>
  </wsdl:message>
  <wsdl:message name="RequestSecurityTokenResponseCollectionMsg">
    <wsdl:part name="responseCollection"
               element="wst:RequestSecurityTokenResponseCollection"/>
  </wsdl:message>

  <!-- This portType an example of a Requestor (or other) endpoint that
         Accepts SOAP-based challenges from a Security Token Service -->
  <wsdl:portType name="WSSecurityRequestor">
    <wsdl:operation name="Challenge">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an STS supporting full protocol -->
  <wsdl:portType name="STS">
    <wsdl:operation name="Cancel">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/CancelFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Issue">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal"
        message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/RenewFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/ValidateFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <wsdl:input
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KET"
        message="tns:RequestSecurityTokenMsg"/>
      <wsdl:output
        wsam:Action="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTR/KETFinal"
        message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <wsdl:input message="tns:RequestSecurityTokenCollectionMsg"/>
      <wsdl:output message="tns:RequestSecurityTokenResponseCollectionMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <!-- This portType is an example of an endpoint that accepts
         Unsolicited RequestSecurityTokenResponse messages -->
  <wsdl:portType name="SecurityTokenResponseService">
    <wsdl:operation name="RequestSecurityTokenResponse">
      <wsdl:input message="tns:RequestSecurityTokenResponseMsg"/>
    </wsdl:operation>
  </wsdl:portType>

  <wsdl:binding name="UT_Binding" type="wstrust:STS">
    <wsp:PolicyReference URI="#UT_policy"/>
    <soap:binding style="document"
                  transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="Issue">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Validate">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Validate"/>
      <wsdl:input>
        <wsp:PolicyReference
          URI="#Input_policy"/>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <wsp:PolicyReference
          URI="#Output_policy"/>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Cancel">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Cancel"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="Renew">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Renew"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="KeyExchangeToken">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/KeyExchangeToken"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
    <wsdl:operation name="RequestCollection">
      <soap:operation
        soapAction="http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/RequestCollection"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>

  <wsdl:service name="SecurityTokenService">
    <wsdl:port name="UT_Port" binding="tns:UT_Binding">
      <soap:address location="http://localhost:8080/SecurityTokenService/UT"/>
    </wsdl:port>
  </wsdl:service>

  <wsp:Policy wsu:Id="UT_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <wsap10:UsingAddressing/>
        <sp:SymmetricBinding
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:ProtectionToken>
              <wsp:Policy>
                <sp:X509Token
                  sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
                  <wsp:Policy>
                    <sp:RequireDerivedKeys/>
                    <sp:RequireThumbprintReference/>
                    <sp:WssX509V3Token10/>
                  </wsp:Policy>
                </sp:X509Token>
              </wsp:Policy>
            </sp:ProtectionToken>
            <sp:AlgorithmSuite>
              <wsp:Policy>
                <sp:Basic256/>
              </wsp:Policy>
            </sp:AlgorithmSuite>
            <sp:Layout>
              <wsp:Policy>
                <sp:Lax/>
              </wsp:Policy>
            </sp:Layout>
            <sp:IncludeTimestamp/>
            <sp:EncryptSignature/>
            <sp:OnlySignEntireHeadersAndBody/>
          </wsp:Policy>
        </sp:SymmetricBinding>
        <sp:SignedSupportingTokens
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:UsernameToken
              sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
              <wsp:Policy>
                <sp:WssUsernameToken10/>
              </wsp:Policy>
            </sp:UsernameToken>
          </wsp:Policy>
        </sp:SignedSupportingTokens>
        <sp:Wss11
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportRefKeyIdentifier/>
            <sp:MustSupportRefIssuerSerial/>
            <sp:MustSupportRefThumbprint/>
            <sp:MustSupportRefEncryptedKey/>
          </wsp:Policy>
        </sp:Wss11>
        <sp:Trust13
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <wsp:Policy>
            <sp:MustSupportIssuedTokens/>
            <sp:RequireClientEntropy/>
            <sp:RequireServerEntropy/>
          </wsp:Policy>
        </sp:Trust13>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Input_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

  <wsp:Policy wsu:Id="Output_policy">
    <wsp:ExactlyOne>
      <wsp:All>
        <sp:SignedParts
          xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
          <sp:Body/>
          <sp:Header Name="To"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="From"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="FaultTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="ReplyTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="MessageID"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="RelatesTo"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
          <sp:Header Name="Action"
                     Namespace="http://www.w3.org/2005/08/addressing"/>
        </sp:SignedParts>
      </wsp:All>
    </wsp:ExactlyOne>
  </wsp:Policy>

</wsdl:definitions>
STS’s implementation class

The Apache CXF’s STS, SecurityTokenServiceProvider, is a web service provider that is compliant with the protocols and functionality defined by the WS-Trust specification. It has a modular architecture. Many of its components are configurable or replaceable and there are many optional features that are enabled by implementing and configuring plug-ins. Users can customize their own STS by extending from SecurityTokenServiceProvider and overriding the default settings. Extensive information about the CXF’s STS configurable and pluggable components can be found here .

This STS implementation class, SampleSTSHolderOfKey, is a POJO that extends from SecurityTokenServiceProvider. Note that the class is defined with a WebServiceProvider annotation and not a WebService annotation. This annotation defines the service as a Provider-based endpoint, meaning it supports a more messaging-oriented approach to Web services. In particular, it signals that the exchanged messages will be XML documents of some type. SecurityTokenServiceProvider is an implementation of the jakarta.xml.ws.Provider interface. In comparison the WebService annotation defines a (service endpoint interface) SEI-based endpoint which supports message exchange via SOAP envelopes.

As was done in the HolderOfKeyImpl class, the WSS4J annotations EndpointProperties and EndpointProperty are providing endpoint configuration for the CXF runtime. The first EndpointProperty statements declares the Java properties file that contains the (Merlin) crypto configuration information. WSS4J reads this file and extra required information for message handling. The last EndpointProperty statement declares the STSHolderOfKeyCallbackHandler implementation class. It is used to obtain the user’s password for the certificates in the keystore file.

In this implementation we are customizing the operations of token issuance and their static properties.

StaticSTSProperties is used to set select properties for configuring resources in the STS. You may think this is a duplication of the settings made with the WSS4J annotations. The values are the same but the underlying structures being set are different, thus this information must be declared in both places.

The setIssuer setting is important because it uniquely identifies the issuing STS. The issuer string is embedded in issued tokens and, when validating tokens, the STS checks the issuer string value. Consequently, it is important to use the issuer string in a consistent way, so that the STS can recognize the tokens that it has issued.

The setEndpoints call allows the declaration of a set of allowed token recipients by address. The addresses are specified as reg-ex patterns.

TokenIssueOperation has a modular structure. This allows custom behaviors to be injected into the processing of messages. In this case we are overriding the SecurityTokenServiceProvider’s default behavior and performing SAML token processing. CXF provides an implementation of a SAMLTokenProvider which we are using rather than writing our own.

Learn more about the SAMLTokenProvider here .

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsholderofkey;

import org.apache.cxf.annotations.EndpointProperties;
import org.apache.cxf.annotations.EndpointProperty;
import org.apache.cxf.sts.StaticSTSProperties;
import org.apache.cxf.sts.operation.TokenIssueOperation;
import org.apache.cxf.sts.service.ServiceMBean;
import org.apache.cxf.sts.service.StaticService;
import org.apache.cxf.sts.token.provider.SAMLTokenProvider;
import org.apache.cxf.ws.security.sts.provider.SecurityTokenServiceProvider;

import jakarta.xml.ws.WebServiceProvider;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * User: rsearls
 * Date: 3/14/14
 */
@WebServiceProvider(serviceName = "SecurityTokenService",
   portName = "UT_Port",
   targetNamespace = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/",
   wsdlLocation = "WEB-INF/wsdl/holderofkey-ws-trust-1.4-service.wsdl")
//be sure to have dependency on org.apache.cxf module when on AS7, otherwise Apache CXF annotations are ignored
@EndpointProperties(value = {
   @EndpointProperty(key = "ws-security.signature.properties", value = "stsKeystore.properties"),
   @EndpointProperty(key = "ws-security.callback-handler", value = "org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsholderofkey.STSHolderOfKeyCallbackHandler")
})
public class SampleSTSHolderOfKey extends SecurityTokenServiceProvider
{

   public SampleSTSHolderOfKey() throws Exception
   {
      super();

      StaticSTSProperties props = new StaticSTSProperties();
      props.setSignatureCryptoProperties("stsKeystore.properties");
      props.setSignatureUsername("mystskey");
      props.setCallbackHandlerClass(STSHolderOfKeyCallbackHandler.class.getName());
      props.setEncryptionCryptoProperties("stsKeystore.properties");
      props.setEncryptionUsername("myservicekey");
      props.setIssuer("DoubleItSTSIssuer");

      List<ServiceMBean> services = new LinkedList<ServiceMBean>();
      StaticService service = new StaticService();
      service.setEndpoints(Arrays.asList(
         "https://localhost:(\\d)*/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService",
         "https://\\[::1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService",
         "https://\\[0:0:0:0:0:0:0:1\\]:(\\d)*/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService"
      ));

      services.add(service);

      TokenIssueOperation issueOperation = new TokenIssueOperation();
      issueOperation.getTokenProviders().add(new SAMLTokenProvider());
      issueOperation.setServices(services);
      issueOperation.setStsProperties(props);
      this.setIssueOperation(issueOperation);

   }
}
HolderOfKeyCallbackHandler

STSHolderOfKeyCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.stsholderofkey;

import org.jboss.wsf.stack.cxf.extensions.security.PasswordCallbackHandler;

import java.util.HashMap;
import java.util.Map;

/**
 * User: rsearls
 * Date: 3/19/14
 */
public class STSHolderOfKeyCallbackHandler extends PasswordCallbackHandler
{
   public STSHolderOfKeyCallbackHandler()
   {
      super(getInitMap());
   }

   private static Map<String, String> getInitMap()
   {
      Map<String, String> passwords = new HashMap<String, String>();
      passwords.put("mystskey", "stskpass");
      passwords.put("alice", "clarinet");
      return passwords;
   }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File stsKeystore.properties contains this information.

File servicestore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=stsspass
org.apache.ws.security.crypto.merlin.keystore.file=stsstore.jks
MANIFEST.MF

When deployed on WildFly, this application requires access to the JBossWS and Apache CXF APIs provided in modules org.jboss.ws.cxf.jbossws-cxf-client. The org.jboss.ws.cxf.sts module is also needed to build the STS configuration in the SampleSTSHolderOfKey constructor. The dependency statement directs the server to provide them at deployment.

Manifest-Version:1.0
Ant-Version: Apache Ant1.8.2
Created-By:1.7.0_25-b15 (Oracle Corporation)
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client,org.jboss.ws.cxf.sts
Web service requester

This section examines the crucial elements in calling a web service that implements endpoint security as described in the SAML Holder-Of-Key scenario. The components that will be discussed are.

  • web service requester’s implementation

  • ClientCallbackHandler

  • Crypto properties and keystore files

Web service requester Implementation

The ws-requester, the client, uses standard procedures for creating a reference to the web service. To address the endpoint security requirements, the web service’s "Request Context" is configured with the information needed in message generation. In addition, the STSClient that communicates with the STS is configured with similar values. Note the key strings ending with a ".it" suffix. This suffix flags these settings as belonging to the STSClient. The internal CXF code assigns this information to the STSClient that is auto-generated for this service call.

There is an alternate method of setting up the STSCLient. The user may provide their own instance of the STSClient. The CXF code will use this object and not auto-generate one. When providing the STSClient in this way, the user must provide a org.apache.cxf.Bus for it and the configuration keys must not have the ".it" suffix. This is used in the ActAs and OnBehalfOf examples.

String serviceURL = "https://" + getServerHost() + ":8443/jaxws-samples-wsse-policy-trust-holderofkey/HolderOfKeyService";

final QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/holderofkeywssecuritypolicy", "HolderOfKeyService");
final URL wsdlURL = new URL(serviceURL + "?wsdl");
Service service = Service.create(wsdlURL, serviceName);
HolderOfKeyIface proxy = (HolderOfKeyIface) service.getPort(HolderOfKeyIface.class);

Map<String, Object> ctx = ((BindingProvider)proxy).getRequestContext();

// set the security related configuration information for the service "request"
ctx.put(SecurityConstants.CALLBACK_HANDLER, new ClientCallbackHandler());
ctx.put(SecurityConstants.SIGNATURE_PROPERTIES,
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES,
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.SIGNATURE_USERNAME, "myclientkey");
ctx.put(SecurityConstants.ENCRYPT_USERNAME, "myservicekey");

//-- Configuration settings that will be transfered to the STSClient
// "alice" is the name provided for the WSS Username. Her password will
// be retreived from the ClientCallbackHander by the STSClient.
ctx.put(SecurityConstants.USERNAME + ".it", "alice");
ctx.put(SecurityConstants.CALLBACK_HANDLER + ".it", new ClientCallbackHandler());
ctx.put(SecurityConstants.ENCRYPT_PROPERTIES + ".it",
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.ENCRYPT_USERNAME + ".it", "mystskey");
ctx.put(SecurityConstants.STS_TOKEN_USERNAME + ".it", "myclientkey");
ctx.put(SecurityConstants.STS_TOKEN_PROPERTIES + ".it",
  Thread.currentThread().getContextClassLoader().getResource(
  "META-INF/clientKeystore.properties"));
ctx.put(SecurityConstants.STS_TOKEN_USE_CERT_FOR_KEYINFO + ".it", "true");

proxy.sayHello();
ClientCallbackHandler

ClientCallbackHandler is a callback handler for the WSS4J Crypto API. It is used to obtain the password for the private key in the keystore. This class enables CXF to retrieve the password of the user name to use for the message signature. Note that "alice" and her password have been provided here. This information is not in the (JKS) keystore but provided in the WildFly security domain. It was declared in file jbossws-users.properties.

package org.jboss.test.ws.jaxws.samples.wsse.policy.trust.shared;

import java.io.IOException;
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 ClientCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        for (int i = 0; i < callbacks.length; i++) {
            if (callbacks[i] instanceof WSPasswordCallback) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                if ("myclientkey".equals(pc.getIdentifier())) {
                    pc.setPassword("ckpass");
                    break;
                } else if ("alice".equals(pc.getIdentifier())) {
                    pc.setPassword("clarinet");
                    break;
                } else if ("bob".equals(pc.getIdentifier())) {
                    pc.setPassword("trombone");
                    break;
                } else if ("myservicekey".equals(pc.getIdentifier())) {  // rls test  added for bearer test
                   pc.setPassword("skpass");
                   break;
                }
            }
        }
    }
}
Crypto properties and keystore files

WSS4J’s Crypto implementation is loaded and configured via a Java properties file that contains Crypto configuration data. The file contains implementation-specific properties such as a keystore location, password, default alias and the like. This application is using the Merlin implementation. File clientKeystore.properties contains this information.

File clientstore.jks, is a Java KeyStore (JKS) repository. It contains self signed certificates for myservicekey and mystskey. Self signed certificates are not appropriate for production use.

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=cspass
org.apache.ws.security.crypto.merlin.keystore.alias=myclientkey
org.apache.ws.security.crypto.merlin.keystore.file=META-INF/clientstore.jks

5.14. WS-Reliable Messaging

JBoss Web Services inherits full WS-Reliable Messaging capabilities from the underlying Apache CXF implementation. At the time of writing, Apache CXF provides support for the WS-Reliable Messaging 1.0 (February 2005) version of the specification.

5.14.1. Enabling WS-Reliable Messaging

WS-Reliable Messaging is implemented internally in Apache CXF through a set of interceptors that deal with the low level requirements of the reliable messaging protocol. In order for enabling WS-Reliable Messaging, users need to either:

  • consume a WSDL contract that specifies proper WS-Reliable Messaging policies / assertions

  • manually add / configure the reliable messaging interceptors

  • specify the reliable messaging policies in an optional CXF Spring XML descriptor

  • specify the Apache CXF reliable messaging feature in an optional CXF Spring XML descriptor

The former approach relies on the Apache CXF WS-Policy engine and is the only portable one. The other approaches are Apache CXF proprietary ones, however they allow for fine-grained configuration of protocol aspects that are not covered by the WS-Reliable Messaging Policy. More details are available in the Apache CXF documentation .

5.14.2. Example

In this example we configure WS-Reliable Messaging endpoint and client through the WS-Policy support.

Endpoint

We go with a contract-first approach, so we start by creating a proper WSDL contract, containing the WS-Reliable Messaging and WS-Addressing policies (the latter is a requirement of the former):

<?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">

  <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">
    <wsp:Policy>
      <!-- WS-Addressing and basic WS-Reliable Messaging policy assertions -->
      <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>
    <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:8080/jaxws-samples-wsrm-api"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

Then we use the wsconsume tool to generate both standard JAX-WS client and endpoint.

We provide a basic JAX-WS implementation for the endpoint, nothing special in it:

package org.jboss.test.ws.jaxws.samples.wsrm.service;

import jakarta.jws.Oneway;
import jakarta.jws.WebMethod;
import jakarta.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;
   }
}

Finally we package the generated POJO endpoint together with a basic web.xml the usual way and deploy to the application server. The webservices stack automatically detects the policies and enables WS-Reliable Messaging.

Client

The endpoint advertises his RM capabilities (and requirements) through the published WSDL and the client is required to also enable WS-RM for successfully exchanging messages with the server.

A regular JAX-WS client is enough if the user does not need to tune any specific detail of the RM subsystem.

QName serviceName = new QName("http://www.jboss.org/jbossws/ws-extensions/wsrm", "SimpleService");
URL wsdlURL = new URL("http://localhost:8080/jaxws-samples-wsrm-api?wsdl");
Service service = Service.create(wsdlURL, serviceName);
proxy = (SimpleService)service.getPort(SimpleService.class);
proxy.echo("Hello World!");
Additional configuration

Fine-grained tuning of WS-Reliable Messaging engine requires setting up proper RM features and attach them for instance to the client proxy. Here is an example:

package org.jboss.test.ws.jaxws.samples.wsrm.client;

//...
import jakarta.xml.ws.Service;
import org.apache.cxf.ws.rm.feature.RMFeature;
import org.apache.cxf.ws.rm.manager.AcksPolicyType;
import org.apache.cxf.ws.rm.manager.DestinationPolicyType;
import org.apache.cxf.ws.rmp.v200502.RMAssertion;
import org.apache.cxf.ws.rmp.v200502.RMAssertion.AcknowledgementInterval;
import org.jboss.test.ws.jaxws.samples.wsrm.generated.SimpleService;

//...
Service service = Service.create(wsdlURL, serviceName);

RMFeature feature = new RMFeature();
RMAssertion rma = new RMAssertion();
RMAssertion.BaseRetransmissionInterval bri = new RMAssertion.BaseRetransmissionInterval();
bri.setMilliseconds(4000L);
rma.setBaseRetransmissionInterval(bri);
AcknowledgementInterval ai = new AcknowledgementInterval();
ai.setMilliseconds(2000L);
rma.setAcknowledgementInterval(ai);
feature.setRMAssertion(rma);
DestinationPolicyType dp = new DestinationPolicyType();
AcksPolicyType ap = new AcksPolicyType();
ap.setIntraMessageThreshold(0);
dp.setAcksPolicy(ap);
feature.setDestinationPolicy(dp);

SimpleService proxy = (SimpleService)service.getPort(SimpleService.class, feature);
proxy.echo("Hello World");

The same can of course be achieved by factoring the feature into a custom pojo extending org.apache.cxf.ws.rm.feature.RMFeature and setting the obtained property in a client configuration:

package org.jboss.test.ws.jaxws.samples.wsrm.client;

import org.apache.cxf.ws.rm.feature.RMFeature;
import org.apache.cxf.ws.rm.manager.AcksPolicyType;
import org.apache.cxf.ws.rm.manager.DestinationPolicyType;
import org.apache.cxf.ws.rmp.v200502.RMAssertion;
import org.apache.cxf.ws.rmp.v200502.RMAssertion.AcknowledgementInterval;

public class CustomRMFeature extends RMFeature
{
   public CustomRMFeature() {
      super();
      RMAssertion rma = new RMAssertion();
      RMAssertion.BaseRetransmissionInterval bri = new RMAssertion.BaseRetransmissionInterval();
      bri.setMilliseconds(4000L);
      rma.setBaseRetransmissionInterval(bri);
      AcknowledgementInterval ai = new AcknowledgementInterval();
      ai.setMilliseconds(2000L);
      rma.setAcknowledgementInterval(ai);
      super.setRMAssertion(rma);
      DestinationPolicyType dp = new DestinationPolicyType();
      AcksPolicyType ap = new AcksPolicyType();
      ap.setIntraMessageThreshold(0);
      dp.setAcksPolicy(ap);
      super.setDestinationPolicy(dp);
   }
}
  1. this is how the jaxws-client-config.xml descriptor would look:

<?xml version="1.0" encoding="UTF-8"?>

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:5.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jakartaee="https://jakarta.ee/xml/ns/jakartaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:5.0 schema/jbossws-jaxws-config_5_0.xsd">

  <client-config>
    <config-name>Custom Client Config</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>org.jboss.test.ws.jaxws.samples.wsrm.client.CustomRMFeature</property-value>
    </property>
  </client-config>

</jaxws-config>
  1. and this is how the client would set the configuration:

import org.jboss.ws.api.configuration.ClientConfigUtil;
import org.jboss.ws.api.configuration.ClientConfigurer;

//...
Service service = Service.create(wsdlURL, serviceName);
SimpleService proxy = (SimpleService)service.getPort(SimpleService.class);

ClientConfigurer configurer = ClientConfigUtil.resolveClientConfigurer();
configurer.setConfigProperties(proxy, "META-INF/jaxws-client-config.xml", "Custom Client Config");
proxy.echo("Hello World!");

5.15. SOAP over JMS

JBoss Web Services allows communication over the JMS transport. The functionality comes from Apache CXF support for the SOAP over Java Message Service 1.0 specification, which is aimed at a set of standards for interoperable transport of SOAP messages over JMS .

On top of Apache CXF functionalities, the JBossWS integration allows users to deploy WS archives containing both JMS and HTTP endpoints the same way as they do for basic HTTP WS endpoints (in war archives). The webservices layer of WildFly takes care of looking for JMS enpdoints in the deployed archive and starts them delegating to the Apache CXF core similarly as with HTTP endpoints.

5.15.1. Configuring SOAP over JMS

As per specification, the SOAP over JMS transport configuration is controlled by proper elements and attributes in the binding and service elements of the WSDL contract. A JMS endpoint is usually developed using a contract-first approach.

The Apache CXF documentation covers all the details of the supported configurations. The minimum configuration implies:

  • setting a proper JMS URI in the soap:address location [1]

  • providing a JNDI connection factory name to be used for connecting to the queues [2]

  • setting the transport binding [3]

<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...

<wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
  <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/> <!-- 3 -->
  <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="HelloWorldService">
  <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName> <!-- 2 -->
  <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
    <soap:address location="jms:queue:testQueue"/> <!-- 1 -->
  </wsdl:port>
</wsdl:service>

Apache CXF takes care of setting up the JMS transport for endpoint implementations whose @WebService annotation points to a port declared for JMS transport as explained above.

Note

JBossWS currently supports POJO endpoints only for JMS transport use. The endpoint classes can be deployed as part of jar or war archives.

The web.xml descriptor in war archives doesn’t need any entry for JMS endpoints.

5.15.2. Examples

JMS endpoint only deployment

In this example we create a simple endpoint relying on SOAP over JMS and deploy it as part of a jar archive.

The endpoint is created using wsconsume tool from a WSDL contract such as:

<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms" version="1.0" xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="echo" type="tns:echo"/>
<xs:element name="echoResponse" type="tns:echoResponse"/>
<xs:complexType name="echo">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
<xs:complexType name="echoResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
  </wsdl:types>
  <wsdl:message name="echoResponse">
    <wsdl:part element="tns:echoResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="echo">
    <wsdl:part element="tns:echo" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloWorld">
    <wsdl:operation name="echo">
      <wsdl:input message="tns:echo" name="echo">
    </wsdl:input>
      <wsdl:output message="tns:echoResponse" name="echoResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/>
    <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="HelloWorldService">
    <soapjms:jndiConnectionFactoryName>java:jms/RemoteConnectionFactory</soapjms:jndiConnectionFactoryName>
    <soapjms:jndiInitialContextFactory>org.jboss.naming.remote.client.InitialContextFactory</soapjms:jndiInitialContextFactory>
    <soapjms:jndiURL>http-remoting://myhost:8080</soapjms:jndiURL>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
  </wsdl:service>
  <wsdl:service name="HelloWorldServiceLocal">
    <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
Important

The HelloWorldImplPort here is meant for using the testQueue that has to be created before deploying the endpoint.

At the time of writing, java:/ConnectionFactory is the default connection factory JNDI location.

For allowing remote JNDI lookup of the connection factory, a specific service ( HelloWorldService ) for remote clients is added to the WSDL. The java:jms/RemoteConnectionFactory is the JNDI location of the same connection factory mentioned above, except it’s exposed for remote lookup. The soapjms:jndiInitialContextFactory and soap:jmsjndiURL complete the remote connection configuration: they depends on the actual WildFly container the service is running on and specify the the initial context factory class to use and the JNDI registry address.

Important

Look at the application server domain to see the configured connection factory JNDI locations.

The endpoint implementation is a JAX-WS POJO using @WebService annotation to refer to the consumed contract:

package org.jboss.test.ws.jaxws.cxf.jms;

import jakarta.jws.WebService;

@WebService
(
   portName = "HelloWorldImplPort",
   serviceName = "HelloWorldServiceLocal",
   wsdlLocation = "META-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      return input;
   }
}
Note

The endpoint implementation references the HelloWorldServiceLocal wsdl service, so that the local JNDI connection factory location is used for starting the endpoint on server side.

The final step is to package the generated service endpoint interface, the endpoint implementation and the WSDL file in a jar archive and deploy it:

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-cxf-jms-only-deployment.jar
     0 Thu Jun 23 15:18:44 CEST 2011 META-INF/
   129 Thu Jun 23 15:18:42 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 23 15:18:42 CEST 2011 org/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/
   313 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/HelloWorld.class
  1173 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/HelloWorldImpl.class
     0 Thu Jun 23 15:18:40 CEST 2011 META-INF/wsdl/
  3074 Thu Jun 23 15:18:40 CEST 2011 META-INF/wsdl/HelloWorldService.wsdl
Note

A dependency on org.apache.activemq.artemis module needs to be added in MANIFEST.MF when deploying to WildFly.

Manifest-Version: 1.0

Ant-Version: Apache Ant 1.7.1

Created-By: 17.0-b16 (Sun Microsystems Inc.)

Dependencies: org.apache.activemq.artemis

A JAX-WS client can interact with the JMS endpoint the usual way:

URL wsdlUrl = ...
//start another bus to avoid affecting the one that could already be assigned to the current thread - optional but highly suggested
Bus bus = BusFactory.newInstance().createBus();
BusFactory.setThreadDefaultBus(bus);
try
{
   QName serviceName = new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldService");
   Service service = Service.create(wsdlUrl, serviceName);
   HelloWorld proxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldImplPort"), HelloWorld.class);
   setupProxy(proxy);
   proxy.echo("Hi");
}
finally
{
   bus.shutdown(true);
}
Important

The WSDL location URL needs to be retrieved in a custom way, depending on the client application. Given the endpoint is JMS only, there’s no automatically published WSDL contract.

In order for performing the remote invocation (which internally goes through remote JNDI lookup of the connection factory), the calling user credentials need to be set into the Apache CXF JMSConduit:

private void setupProxy(HelloWorld proxy) {
   JMSConfiguration config = conduit.getJmsConfig();
   config.setUserName(JBossWSTestHelper.getTestUsername());
   config.setPassword(JBossWSTestHelper.getTestPassword());
   Properties props = conduit.getJmsConfig().getJndiEnvironment();
   props.put(Context.SECURITY_PRINCIPAL, JBossWSTestHelper.getTestUsername());
   props.put(Context.SECURITY_CREDENTIALS, JBossWSTestHelper.getTestPassword());
}
Important

Look at the WildFly domain and messaging configuration to see the security requirements. At the time of writing, a user with guest role is required and that’s internally checked using the other security domain.

Once the endpoint is exposed over JMS transport, any plain JMS client can also be used to send messages to the webservice endpoint. Look at the SOAP over JMS spec details and code the client similarly to

Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
env.put(Context.PROVIDER_URL, "http-remoting://myhost:8080");
env.put(Context.SECURITY_PRINCIPAL, "user");
env.put(Context.SECURITY_CREDENTIALS, "password");
InitialContext context = new InitialContext(env);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("jms/RemoteConnectionFactory");
Queue reqQueue = (Queue)context.lookup("jms/queue/test");
Queue resQueue = (Queue)context.lookup("jms/queue/test");
QueueConnection con = connectionFactory.createQueueConnection("user", "password");
QueueSession session = con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver receiver = session.createReceiver(resQueue);
ResponseListener responseListener = new ResponseListener(); //a custom response listener...
receiver.setMessageListener(responseListener);
con.start();
TextMessage message = session.createTextMessage(reqMessage);
message.setJMSReplyTo(resQueue);

//setup SOAP-over-JMS properties...
message.setStringProperty("SOAPJMS_contentType", "text/xml");
message.setStringProperty("SOAPJMS_requestURI", "jms:queue:testQueue");

QueueSender sender = session.createSender(reqQueue);
sender.send(message);
sender.close();

...
JMS and HTTP endpoints deployment

In this example we create a deployment containing an endpoint that serves over both HTTP and JMS transports.

We from a WSDL contract such as below (please note we’ve two binding / portType for the same service ):

<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms" version="1.0"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="echo" type="tns:echo"/>
<xs:element name="echoResponse" type="tns:echoResponse"/>
<xs:complexType name="echo">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
<xs:complexType name="echoResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
  </wsdl:types>
  <wsdl:message name="echoResponse">
    <wsdl:part element="tns:echoResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="echo">
    <wsdl:part element="tns:echo" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloWorld">
    <wsdl:operation name="echo">
      <wsdl:input message="tns:echo" name="echo">
    </wsdl:input>
      <wsdl:output message="tns:echoResponse" name="echoResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/>
    <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:binding name="HttpHelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <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="HelloWorldService">
    <soapjms:jndiConnectionFactoryName>java:jms/RemoteConnectionFactory</soapjms:jndiConnectionFactoryName>
    <soapjms:jndiInitialContextFactory>org.jboss.naming.remote.client.InitialContextFactory</soapjms:jndiInitialContextFactory>
    <soapjms:jndiURL>remote://localhost:4447</soapjms:jndiURL>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
    <wsdl:port binding="tns:HttpHelloWorldServiceSoapBinding" name="HttpHelloWorldImplPort">
      <soap:address location="http://localhost:8080/jaxws-cxf-jms-http-deployment"/>
    </wsdl:port>
  </wsdl:service>
  <wsdl:service name="HelloWorldServiceLocal">
    <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
</wsdl:definitions>

The same considerations of the previous example regarding the JMS queue and JNDI connection factory still apply. Here we can implement the endpoint in multiple ways, either with a common implementation class that’s extended by the JMS and HTTP ones, or keep the two implementation classes independent and just have them implement the same service endpoint interface:

package org.jboss.test.ws.jaxws.cxf.jms_http;

import jakarta.jws.WebService;

@WebService
(
   portName = "HelloWorldImplPort",
   serviceName = "HelloWorldServiceLocal",
   wsdlLocation = "WEB-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms_http.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      System.out.println("input: " + input);
      return input;
   }
}
package org.jboss.test.ws.jaxws.cxf.jms_http;

import jakarta.jws.WebService;

@WebService
(
   portName = "HttpHelloWorldImplPort",
   serviceName = "HelloWorldService",
   wsdlLocation = "WEB-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms_http.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HttpHelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      System.out.println("input (http): " + input);
      return "(http) " + input;
   }
}

Both classes are packaged together the service endpoint interface and the WSDL file in a war archive:

alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-cxf-jms-http-deployment.war
     0 Thu Jun 23 15:18:44 CEST 2011 META-INF/
   129 Thu Jun 23 15:18:42 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 23 15:18:44 CEST 2011 WEB-INF/
   569 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 23 15:18:44 CEST 2011 WEB-INF/classes/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/
   318 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HelloWorld.class
  1192 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HelloWorldImpl.class
  1246 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HttpHelloWorldImpl.class
     0 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/wsdl/
  3068 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/wsdl/HelloWorldService.wsdl

A web.xml descriptor is included to trigger the HTTP endpoint publish:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">
  <servlet>
    <servlet-name>EndpointServlet</servlet-name>
    <servlet-class>org.jboss.test.ws.jaxws.cxf.jms_http.HttpHelloWorldImpl</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>EndpointServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
Important

The MANIFEST.MF needs to declare a dependency on org.apache.activemq.artemis module when deploying to WildFly.

Finally, the JAX-WS client can interact with both JMS and HTTP endpoints as usual:

//start another bus to avoid affecting the one that could already be assigned to current thread - optional but highly suggested
Bus bus = BusFactory.newInstance().createBus();
BusFactory.setThreadDefaultBus(bus);
try
{
   QName serviceName = new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldService");
   Service service = Service.create(wsdlUrl, serviceName);

   //JMS test
   HelloWorld proxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldImplPort"), HelloWorld.class);
   setupProxy(proxy);
   proxy.echo("Hi");
   //HTTP test
   HelloWorld httpProxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HttpHelloWorldImplPort"), HelloWorld.class);
   httpProxy.echo("Hi");
}
finally
{
   bus.shutdown(true);
}
Use of Endpoint.publish() API

An alternative to deploying an archive containing JMS endpoints is starting them directly using the JAX-WS Endpoint.publish(..) API.

It is as easy as doing:

Object implementor = new HelloWorldImpl();
Endpoint ep = Endpoint.publish("jms:queue:testQueue", implementor);
try
{
   //use or let others use the endpoint
}
finally
{
   ep.stop();
}

where HelloWorldImpl is a POJO endpoint implementation referencing a JMS port in a given WSDL contract, as explained in the previous examples.

The main difference among the deployment approach is in the direct control and responsibility over the endpoint lifecycle ( start/publish and stop ).

5.16. HTTP Proxy

The HTTP Proxy related functionalities of JBoss Web Services are provided by the Apache CXF http transport layer.

The suggested configuration mechanism when running JBoss Web Services is explained below; for further information please refer to the Apache CXF documentation .

5.16.1. Configuration

The HTTP proxy configuration for a given JAX-WS client can be set in the following ways:

  • through the http.proxyHost and http.proxyPort system properties, or

  • leveraging the org.apache.cxf.transport.http.HTTPConduit options

The former is a JVM level configuration; for instance, assuming the http proxy is currently running at http://localhost:9934 , here is the setup:

System.getProperties().setProperty("http.proxyHost", "localhost");
System.getProperties().setProperty("http.proxyPort", 9934);

The latter is a client stub/port level configuration: the setup is performed on the HTTPConduit object that’s part of the Apache CXF Client abstraction.

import org.apache.cxf.configuration.security.ProxyAuthorizationPolicy;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.transports.http.configuration.ProxyServerType;
...

Service service = Service.create(wsdlURL, new QName("http://org.jboss.ws/jaxws/cxf/httpproxy", "HelloWorldService"));
HelloWorld port = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/httpproxy", "HelloWorldImplPort"), HelloWorld.class);

Client client = ClientProxy.getClient(port);
HTTPConduit conduit = (HTTPConduit)client.getConduit();
ProxyAuthorizationPolicy policy = new ProxyAuthorizationPolicy();
policy.setAuthorizationType("Basic");
policy.setUserName(PROXY_USER);
policy.setPassword(PROXY_PWD);
conduit.setProxyAuthorization(policy);

port.echo("Foo");

The ProxyAuthorizationPolicy also allows for setting the authotization type as well as the username / password to be used.

Speaking of authorization and authentication, please note that the JDK already features the java.net.Authenticator facility, which is used whenever opening a connection to a given URL requiring a http proxy. Users might want to set a custom Authenticator for instance when needing to read WSDL contracts before actually calling into the JBoss Web Services / Apache CXF code; here is an example:

import java.net.Authenticator;
import java.net.PasswordAuthentication;
...
public class ProxyAuthenticator extends Authenticator
{
   private String user, password;

   public ProxyAuthenticator(String user, String password)
   {
      this.user = user;
      this.password = password;
   }

   protected PasswordAuthentication getPasswordAuthentication()
   {
      return new PasswordAuthentication(user, password.toCharArray());
   }
}

...

Authenticator.setDefault(new ProxyAuthenticator(PROXY_USER, PROXY_PWD));

5.17. WS-Discovery

Apache CXF includes support for Web Services Dynamic Discovery ( WS-Discovery ), which is a protocol to enable dynamic discovery of services available on the local network. The protocol implies using a UDP based multicast transport to announce new services and probe for existing services. A managed mode where a discovery proxy is used to reduce the amount of required multicast traffic is also covered by the protocol.

JBossWS integrates the WS-Discovery functionalities provided by Apache CXF into the application server.

5.17.1. Enabling WS-Discovery

Apache CXF enables WS-Discovery depending on the availability of its runtime component; given that’s always shipped in the application server, JBossWS integration requires using the cxf.ws-discovery.enabled usage for enabling WS-Discovery for a given deployment. By default WS-Discovery is disabled on the application server. Below is an example of jboss-webservices.xml descriptor to be used for enabling WS-Discovery :

<webservices xmlns="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  version="1.3" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">

  <property>
    <name>cxf.ws-discovery.enabled</name>
    <value>true</value>
  </property>

</webservices>

By default, a WS-Discovery service endpoint (SOAP-over-UDP bound) will be started the first time a WS-Discovery enabled deployment is processed on the application server. Every ws endpoint belonging to WS-Discovery enabled deployments will be automatically registered into such a WS-Discovery service endpoint ( Hello messages). The service will reply to Probe and Resolve messages received on UDP port 3702 (including multicast messages sent to IPv4 address 239.255.255.250 , as per specification ). Endpoints will eventually be automatically unregistered using Bye messages upon undeployment.

5.17.2. Probing services

Apache CXF comes with a WS-Discovery API that can be used to probe / resolve services. When running in-container, a JBoss Modules dependency to the the org.apache.cxf.impl module is to be set to have access to WS-Discovery client functionalities.

The org.apache.cxf.ws.discovery.WSDiscoveryClient class provides the probe and resolve methods which also accepts filters on scopes. Users can rely on them for locating available endpoints on the network. Please have a look at the JBossWS testsuite which includes a sample on CXF WS-Discovery usage.

5.18. WS-Policy

5.18.1. Apache CXF WS-Policy support

JBossWS policy support rely on the Apache CXF WS-Policy framework, which is compliant with the Web Services Policy 1.5 - Framework and Web Services Policy 1.5 - Attachment specifications. Users can work with policies in different ways:

  • by adding policy assertions to wsdl contracts and letting the runtime consume them and behave accordingly;

  • by specifying endpoint policy attachments using either CXF annotations or features.

Of course users can also make direct use of the Apache CXF policy framework, defining custom assertions , etc.

Finally, JBossWS provides some additional annotations for simplified policy attachment.

Contract-first approach

WS-Policies can be attached and referenced in wsdl elements (the specifications describe all possible alternatives). Apache CXF automatically recognizes, reads and uses policies defined in the wsdl.

Users should hence develop endpoints using the contract-first approach, that is explicitly providing the contract for their services. Here is a excerpt taken from a wsdl including a WS-Addressing policy:

<wsdl:definitions name="Foo" targetNamespace="http://ws.jboss.org/foo"
...
<wsdl:service name="FooService">
    <wsdl:port binding="tns:FooBinding" name="FooPort">
        <soap:address location="http://localhost:80800/foo"/>
        <wsp:Policy xmlns:wsp="http://www.w3.org/ns/ws-policy">
             <wsam:Addressing xmlns:wsam="http://www.w3.org/2007/02/addressing/metadata">
                 <wsp:Policy/>
              </wsam:Addressing>
         </wsp:Policy>
    </wsdl:port>
</wsdl:service>
</wsdl:definitions>

Of course, CXF also acts upon policies specified in wsdl documents consumed on client side.

Code-first approach

For those preferring code-first (java-first) endpoint development, Apache CXF comes with org.apache.cxf.annotations.Policy and org.apache.cxf.annotations.Policies annotations to be used for attaching policy fragments to the wsdl generated at deploy time.

Here is an example of a code-first endpoint including @Policy annotation:

import jakarta.jws.WebService;
import org.apache.cxf.annotations.Policy;

@WebService(portName = "MyServicePort",
            serviceName = "MyService",
            name = "MyServiceIface",
            targetNamespace = "http://www.jboss.org/jbossws/foo")
@Policy(placement = Policy.Placement.BINDING, uri = "JavaFirstPolicy.xml")
public class MyServiceImpl {
   public String sayHello() {
      return "Hello World!";
   }
}

The referenced descriptor is to be added to the deployment and will include the policy to be attached; the attachment position in the contracts is defined through the placement attribute. Here is a descriptor example:

<?xml version="1.0" encoding="UTF-8" ?>
<wsp:Policy wsu:Id="MyPolicy" xmlns:wsp="http://www.w3.org/ns/ws-policy"
    xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <wsp:ExactlyOne>
        <wsp:All>
            <sp:SupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
                <wsp:Policy>
                    <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                        <wsp:Policy>
                            <sp:WssUsernameToken10/>
                        </wsp:Policy>
                    </sp:UsernameToken>
                </wsp:Policy>
            </sp:SupportingTokens>
        </wsp:All>
    </wsp:ExactlyOne>
</wsp:Policy>

5.18.2. JBossWS additions

Policy sets

Both approaches above require users to actually write their policies' assertions; while this offer great flexibility and control of the actual contract, providing the assertions might end up being quite a challenging task for complex policies. For this reason, the JBossWS integration provides policy sets , which are basically pre-defined groups of policy assertions corresponding to well known / common needs. Each set has a label allowing users to specify it in the @org.jboss.ws.api.annotation.PolicySets annotation to have the policy assertions for that set attached to the annotated endpoint. Multiple labels can also be specified. Here is an example of the @PolicySets annotation on a service endpoint interface:

import jakarta.jws.WebService;
import org.jboss.ws.api.annotation.PolicySets;

@WebService(name = "EndpointTwo", targetNamespace = "http://org.jboss.ws.jaxws.cxf/jbws3648")
@PolicySets({"WS-RM_Policy_spec_example", "WS-SP-EX223_WSS11_Anonymous_X509_Sign_Encrypt", "WS-Addressing"})
public interface EndpointTwo
{
   String echo(String input);
}

The three sets specified in @PolicySets will cause the wsdl generated for the endpoint having this interface to be enriched with some policy assertions for WS-RM, WS-Security and WS-Addressing.

The labels' list of known sets is stored in the META-INF/policies/org.jboss.wsf.stack.cxf.extensions.policy.PolicyAttachmentStore file within the jbossws-cxf-client.jar ( org.jboss.ws.cxf:jbossws-cxf-client maven artifact). Actual policy fragments for each set are also stored in the same artifact at META-INF/policies/<set-label>-<attachment-position>.xml .

Here is a list of the available policy sets:

Label Description

WS-Addressing

Basic WS-Addressing policy

WS-RM_Policy_spec_example

The basic WS-RM policy example in the WS-RM specification

WS-SP-EX2121_SSL_UT_Supporting_Token

The group of policy assertions used in the section 2.1.2.1 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX213_WSS10_UT_Mutual_Auth_X509_Sign_Encrypt

The group of policy assertions used in the section 2.1.3 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX214_WSS11_User_Name_Cert_Sign_Encrypt

The group of policy assertions used in the section 2.1.4 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX221_WSS10_Mutual_Auth_X509_Sign_Encrypt

The group of policy assertions used in the section 2.2.1 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX222_WSS10_Mutual_Auth_X509_Sign_Encrypt

The group of policy assertions used in the section 2.2.2 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX223_WSS11_Anonymous_X509_Sign_Encrypt

The group of policy assertions used in the section 2.2.3 example of the WS-Security Policy Examples 1.0 specification

WS-SP-EX224_WSS11_Mutual_Auth_X509_Sign_Encrypt

The group of policy assertions used in the section 2.2.4 example of the WS-Security Policy Examples 1.0 specification

AsymmetricBinding_X509v1_TripleDesRsa15_EncryptBeforeSigning_ProtectTokens

A WS-Security policy for asymmetric binding (encrypt before signing) using X.509v1 tokens, 3DES + RSA 1.5 algorithms and with token protections enabled

AsymmetricBinding_X509v1_GCM256OAEP_ProtectTokens

The same as before, but using custom Apache CXF algorithm suite including GCM 256 + RSA OAEP algorithms

Warning

Always verify the contents of the generated wsdl contract, as policy sets are potentially subject to updates between JBossWS releases. This is especially important when dealing with security related policies; the provided sets are to be considered as convenient configuration options only; users remain responsible for the policies in their contracts.

Tip

The org.jboss.wsf.stack.cxf.extensions.policy.Constants interface has convenient String constants for the available policy set labels.

Tip

If you feel a new set should be added, just propose it by writing the user forum!

5.19. Published WSDL customization

5.19.1. Endpoint address rewrite

JBossWS supports the rewrite of the <soap:address> element of endpoints published in WSDL contracts. This feature is useful for controlling the server address that is advertised to clients for each endpoint. The rewrite mechanism is configured at server level through a set of elements in the webservices subsystem of the WildFly management model. Please refer to the container documentation for details on the options supported in the selected container version. Below is a list of the elements available in the latest WildFly sources:

Name Type Description

modify-wsdl-address

boolean

This boolean enables and disables the address rewrite functionality. When modify-wsdl-address is set to true and the content of <soap:address> is a valid URL, JBossWS will rewrite the URL using the values of wsdl-host and wsdl-port or wsdl-secure-port. When modify-wsdl-address is set to false and the content of <soap:address> is a valid URL, JBossWS will not rewrite the URL. The <soap:address> URL will be used. When the content of <soap:address> is not a valid URL, JBossWS will rewrite it no matter what the setting of modify-wsdl-address. If modify-wsdl-address is set to true and wsdl-host is not defined or explicitly set to ' jbossws.undefined.host _' _ the content of <soap:address> URL is use. JBossWS uses the requester’s host when rewriting the <soap:address> When modify-wsdl-address is not defined JBossWS uses a default value of true.

wsdl-host

string

The hostname / IP address to be used for rewriting <soap:address> . If wsdl-host is set to jbossws.undefined.host , JBossWS uses the requester’s host when rewriting the <soap:address> When wsdl-host is not defined JBossWS uses a default value of ' jbossws.undefined.host '.

wsdl-port

int

Set this property to explicitly define the HTTP port that will be used for rewriting the SOAP address. Otherwise the HTTP port will be identified by querying the list of installed HTTP connectors.

wsdl-secure-port

int

Set this property to explicitly define the HTTPS port that will be used for rewriting the SOAP address. Otherwise the HTTPS port will be identified by querying the list of installed HTTPS connectors.

wsdl-uri-scheme

string

This property explicitly sets the URI scheme to use for rewriting <soap:address> . Valid values are http and https . This configuration overrides scheme computed by processing the endpoint (even if a transport guarantee is specified). The provided values for wsdl-port and wsdl-secure-port (or their default values) are used depending on specified scheme.

wsdl-path-rewrite-rule

string

This string defines a SED substitution command (e.g., 's/regexp/replacement/g') that JBossWS executes against the path component of each <soap:address> URL published from the server. When wsdl-path-rewrite-rule is not defined, JBossWS retains the original path component of each <soap:address> URL. When 'modify-wsdl-address' is set to "false" this element is ignored.

Additionally, users can override the server level configuration by requesting a specific rewrite behavior for a given endpoint deployment. That is achieved by setting one of the following properties within a jboss-webservices.xml descriptor:

Property Corresponding server option

wsdl.soapAddress.rewrite.modify-wsdl-address

modify-wsdl-address

wsdl.soapAddress.rewrite.wsdl-host

wsdl-host

wsdl.soapAddress.rewrite.wsdl-port

wsdl-port

wsdl.soapAddress.rewrite.wsdl-secure-port

wsdl-secure-port

wsdl.soapAddress.rewrite.wsdl-path-rewrite-rule

wsdl-path-rewrite-rule

wsdl.soapAddress.rewrite.wsdl-uri-scheme

wsdl-uri-scheme

Here is an example of partial overriding of the default configuration for a specific deployment:

<?xml version="1.1" encoding="UTF-8"?>
<webservices version="1.2"
  xmlns="http://www.jboss.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee">
  <property>
    <name>wsdl.soapAddress.rewrite.wsdl-uri-scheme</name>
    <value>https</value>
  </property>
  <property>
    <name>wsdl.soapAddress.rewrite.wsdl-host</name>
    <value>foo</value>
  </property>
</webservices>

5.19.2. System property references

System property references wrapped within "@" characters are expanded when found in WSDL attribute and element values. This allows for instance including multiple WS-Policy declarations in the contract and selecting the policy to use depending on a server wide system property; here is an example:

<wsdl:definitions ...>
  ...
  <wsdl:binding name="ServiceOneSoapBinding" type="tns:EndpointOne">
    ...
    <wsp:PolicyReference URI="#@org.jboss.wsf.test.JBWS3628TestCase.policy@"/>
    <wsdl:operation name="echo">
      ...
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="ServiceOne">
    <wsdl:port binding="tns:ServiceOneSoapBinding" name="EndpointOnePort">
      <soap:address location="http://localhost:8080/jaxws-cxf-jbws3628/ServiceOne"/>
    </wsdl:port>
  </wsdl:service>

  <wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" wsu:Id="WS-RM_Policy">
    <wsrmp:RMAssertion xmlns:wsrmp="http://schemas.xmlsoap.org/ws/2005/02/rm/policy">
          ...
    </wsrmp:RMAssertion>
  </wsp:Policy>

  <wsp:Policy xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy"
      xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" wsu:Id="WS-Addressing_policy">
    <wsam:Addressing>
      <wsp:Policy/>
    </wsam:Addressing>
  </wsp:Policy>
</wsdl:definitions>

If the org.jboss.wsf.test.JBWS3628TestCase.policy system property is defined and set to " WS-Addressing_policy ", WS-Addressing will be enabled for the endpoint defined by the contract above.

5.20. Throtlling

The throttling feature allows server to limit the number of request when the server is busy or there are a lot of faults by some requests. This can protect server from being overwhelmed and server resource is used out. From JBossWS 7.2.0, the `JBossWSThrottlingFeature' is provided to support Throtlling for JBossWS and WFLY users. As each ThrotllingFeature needs a ThrolltingManager to do the actual work, the 'EndpointMetricsThrottlingManager' is created to throttle or limit the flow based on the metrics from the webserivce endpoint. 'EndpointMetricsThrottlingManager' can use the throshold for endpoint metric value like requestCount, faultCount etc.

The throttling configuration can be defined in the jbossws-endpoint-config.xml like :

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">

  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.cxf.throttling.HelloWorldImpl</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>##throttlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.JBossWSThrottlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature.throttlingManager</property-name>
      <property-value>##throttlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.EndpointMetricsThrottlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager.requestCountThreshold</property-name>
      <property-value>5</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

This configuration file set a requestCountThreshold "5" to enable the throttling and returns the http response code 419 to the client when the total request count reaches 5. This is totally for demo purpose, please don’t use in any situation except for the test purpose.

Besides the requestPermits,there are other items can be configured with EndpointMetricsThrottlingManager:

  • faultPermit: The number of faults allowed before throttling takes effect."

  • requestPermit: The number of requests allowed before throttling takes effect."

  • averageProcessingTimePermit: The average processing time in milliseconds; if it exceeds this value, throttling takes effect.

  • maxProcessingTimePermit: The maximum processing time in milliseconds; if it exceeds this value, throttling takes effect.

  • minProcessingTimePermit: The minimum processing time in milliseconds; if it exceeds this value, throttling takes effect.

  • totalProcessingTimePermit: The total processing time in milliseconds; if it exceeds this value, throttling takes effect.

  • responseStatusCode: The response code if the throttling takes effect and default is 429.

  • delayTime:When the response code is set to 503, this value in milliseconds will finally be set with Retry-After header in response when throttling takes effect.

To allow users to configure throttling more easily, there is an out-of-the-box RateLimitThrottlingManager that users can utilize to set traffic limits. This RateLimitThrottlingManager enables users to define the permitted number of requests within a specified period. To simplify this process, it offers the permitsPerMin configuration item, which allows users to set the number of permitted requests per minute. This configuration internally sets the period to 60 seconds and adjusts the permitted number of requests based on the user’s specifications in the jaxws-endpoint-config.xml. Here is the configuration example which is using permitsPerMin to limit the 5 requests in one minute:

<?xml version="1.0" encoding="UTF-8"?>

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.cxf.throttling.HelloImpl</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>##throttlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.JBossWSThrottlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature.throttlingManager</property-name>
      <property-value>##throttlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.RateLimitThorttlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager.permitsPerMin</property-name>
      <property-value>5</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

Users can use the period and permitsPerPeriod settings to define the number of requests allowed within any specified time period. Below is an example of the jaxws-endpoint-config.xml configuration to control 5 requests in 30 seconds:

<?xml version="1.0" encoding="UTF-8"?>

<jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
  <endpoint-config>
    <config-name>org.jboss.test.ws.jaxws.cxf.throttling.HelloImpl</config-name>
    <property>
      <property-name>cxf.features</property-name>
      <property-value>##throttlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.JBossWSThrottlingFeature</property-value>
    </property>
    <property>
      <property-name>##throttlingFeature.throttlingManager</property-name>
      <property-value>##throttlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager</property-name>
      <property-value>org.jboss.wsf.stack.cxf.features.throttling.RateLimitThorttlingManager</property-value>
    </property>
    <property>
      <property-name>##throttlingManager.period</property-name>
      <property-value>30</property-value>
    </property>
    <property>
      <property-name>##throttlingManager.permitsPerPeriod</property-name>
      <property-value>5</property-value>
    </property>
  </endpoint-config>
</jaxws-config>

Please note that both of these ThrottlingManagers are based on the web service endpoint metrics and require the web service subsystem’s statistics to be enabled. Before using either of these ThrottlingManagers, ensure that statistics are enabled with the jboss-cli:

./subsystem=webservices:write-attribute(name=statistics-enabled,value=true)

6. JBoss Modules

The JBoss Web Services functionalities are provided by a given set of modules / libraries installed on the server.

On WildFly, those are organized into JBoss Modules modules. In particular the org.jboss.as.webservices.* and org.jboss.ws.* modules belong to the JBossWS - WildFly integration. Users should not need to change anything in them.

While users are allowed to provide their own modules for their custom needs, below is a brief collection of suggestions and hints around modules and webservices development on WildFly.

6.1. Setting module dependencies

On WildFly the user deployment classloader does not have any visibility over JBoss internals; so for instance you can’t directly use JBossWS implementation classes unless you explicitly set a dependency to the corresponding module. As a consequence, users need to declare the module dependencies they want to be added to their deployment.

Important

The JBoss Web Services APIs are always available by default whenever the webservices subsystem is available on AS7. Users just use them, no need for explicit dependencies declaration for those modules.

6.1.1. Using MANIFEST.MF

The convenient method for configuring deployment dependencies is adding them into the MANIFEST.MF file:

Manifest-Version: 1.0
Dependencies: org.jboss.ws.cxf.jbossws-cxf-client services export,foo.bar

Above org.jboss.ws.cxf.jbossws-cxf-client and foo.bar are the modules you want to set dependencies to; services tells the modules framework that you want to import META-INF/services/.. declarations from the dependency, while export exports the classes from the module to any other module that might be depending on the module implicitly created for your deployment.

Note

When using annotations on your endpoints / handlers such as the Apache CXF ones (@InInterceptor, @GZIP, …​) remember to add the proper module dependency in your manifest, otherwise your annotations are not picked up and added to the annotation index by WildFly, resulting in them being silently ignored.

Using JAXB

In order to directly use JAXB contexts, in your client or endpoint running in-container, you need to properly setup a JAXB implementation; that is performed setting the following dependency:

Dependencies: com.sun.xml.bind services export
Using Apache CXF

In order to use Apache CXF APIs and implementation classes you need to add a dependency to the org.apache.cxf (API) module and / or org.apache.cxf.impl (implementation) module:

Dependencies: org.apache.cxf services

Please note that that would not come with any JBossWS-CXF customizations nor additional extensions. For this reason, and generally speaking for simplifying user configuration, a client side aggregation module is available with all the WS dependencies users might need.

Client side WS aggregation module

Whenever you want to use all the JBoss Web Services feature/functionalities, you can set a dependency to the convenient client module.

Dependencies: org.jboss.ws.cxf.jbossws-cxf-client services

Note the services option above: it is strictly required in order for you to get the JBossWS-CXF version of classes that are retrieved using the Service API , the Bus for instance.

Note

Be careful. Issues of misconfiguration here can be quite hard to track down, because the Apache CXF behaviour would be sensibly different.

Important

The services option is almost always needed when declaring dependencies on org.jboss.ws.cxf.jbossws-cxf-client and org.apache.cxf modules. It affects the loading of classes through the Service API , which is used to wire most of the JBossWS components as well as all Apache CXF Bus extensions.

Annotation scanning

The application server uses an annotation index for detecting JAX-WS endpoints in the user deployments. When declaring WS endpoints, whose class belongs to a different module (for instance referring that in the web.xml descriptor), be sure to have an annotations type dependency in place. Without that, your endpoints will be ignored as they won’t appear as annotated classes to the webservices subsystem.

Dependencies: org.foo annotations

6.1.2. Using jboss-deployment-descriptor.xml

In some circumstances, the convenient approach of setting module dependencies in MANIFEST.MF might not work. An example is the need for importing/exporting specific resources from a given module dependency. Users should hence add a jboss-deployment-structure.xml descriptor to their deployment and set module dependencies in it.

7. Build and testsuite framework

7.1. Introduction

The JBossWS project build and testsuites have been completely revisited in version 5.0.0.Beta3. JBossWS now uses the Arquillian framework to run its integration tests against WildFly containers.

There are two test modules in JBossWS' testsuite, cxf-tests and shared-tests . Each test module requires at least one WildFly container to run. Multiple containers are used for modules whose tests can’t run at the same time on the same container. By default, containers are managed (started / stopped) by Arquillian. The JBossWS build system fetches a copy of the required container from the Maven repository, unpacks it, patches it installing the current webservices stack on it and finally hands it over to Arquillian for the testsuite runs. The test framework also allows Arquillian to manage an already available container instance on the local filesystem. Finally, it’s also possible to execute single tests against a locally running container (non-Arquillian managed) and run the tests concurrently.

7.1.1. Prerequisites and requirements

  • Maven version 3.2.2 or higher is required to build and run the testsuite.

  • A unique class name for each test across the testsuite’s three child modules. Classes may have the same package name across the child modules but the full-qualified name must be unique to avoid breaking concurrent tests run.

7.2. Architecture overview

When the build fetches the Wildfly container from the Maven repository, a patched copy is placed in the target/test-server sub-directory of each testsuite module. For instance, you could have:

/modules/testsuite/shared-tests/target/test-server/jbossws-cxf-dist-5.0.0-SNAPSHOT/wildfly-8.1.0.Final

Each container copy is provided with specific standalone mode configuration files ( jbws-testsuite-SOME_IDENTIFIER.xml ) in the standalone/configuration server directory. The contents of such descriptors depends on the tests that are to be run against such container configurations (the most common difference when compared to the vanilla standalone.xml is the setup of additional security domains, system properties, web connectors etc.) Each configuration includes logging setup to ensure logs are written to unique files ( jbws-testsuite-SOME_IDENFIFIER.log ) in standalone/log directory.

7.2.1. Target Container Identification

JBossWS supports the current WildFly release and several previous versions for testing. Maven profiles are used to identify the target container to be used for testing. The naming convention is wildflyXYZ , for example wildfly820 to mean WIldFly 8.2.0.Final.

To run tests against an existing local copy of a WildFly container, the user must specify the absolute path to the server implementation’s home directory using the command line option, -Dserver.home=/foo/bar . The server should not be running, as the build will create various standalone server configurations and start multiple instances on different port numbers. If only a single test or few tests are to be executed, the user can have those executed against live WildFly instances previously started on the same port numbers expected by the tests. Arquillian is configured to detect such scenario and use the available server.

7.2.2. Port Mapping

To facilitate concurrent testing, a port offset has been defined for each of the server configurations. The offsets are defined in the <properties> element of the modules/testsuite/pom.xml file.

7.3. Command Line Options

As any other Maven-based project, JBossWS is built as follows:

mvn -P[profile] -D[options] [phase]

7.3.1. Profile

JBossWS uses Maven profiles to declare the target container and other types of environment setup. Multiple profiles are provided as a comma separated list of profile names. Only a single target container profile is allowed at the same time though.

Profile Description

wildflyXYZ

Designates the target container to use, where XYZ is WildFly’s three digit version number

fast

Declares the tests are to be run concurrently

dist

Explicitly includes dist module in the build; by default this is automatically triggered (only) when a wildflyXYZ profile is set.

testsuite

Explicitly includes the testsuite modules in the build; by default this is automatically triggered (only) when a wildflyXYZ profile is set.

7.3.2. Options

Below is a list of the available build / test options:

Option Description

server.home

Declares the absolute path to a given local server instance.

exclude-udp-tests

Force skipping the UDP tests. This option might be needed when running on a network that does not allow UDP broadcast.

noprepare

Skip integration tests preparation phase, which includes tuning of the server configurations, wsconsume/wsprovide invocations, etc.

debug

Turns on Surefire debugging of integration tests only. Debugging address is 5005.

jboss.bind.address

Starts the containers bound to the specified network interface address.

arquillian.deploymentExportPath

Instructs Arquillian to write the actual test deployments to disk in the specified module sub-directory.

test

Runs the test in the specified comma-separated list of JUnit classes

maven.surefire.debug

Turns on Surefire debugging in any module including tests.

7.3.3. Examples

Build the project, deploy the WS stack to a local copy of WildFly 8.2.0.Final and run the testsuite:

mvn -Pwildfly820 -Dserver.home=/foo/wildfly-8.2.0.Final integration-test

Use WildFly 8.1.0.Final as the target container (letting the build fetch it), patch it with current WS stack and run only test MtomTestCase that is located in the cxf-test module:

mvn -Pwildfly810 integration-test -Dtest="org/jboss/test/ws/jaxws/samples/MtomTestCase"

Build, deploy, then run the tests concurrently. Run till Maven post-integration-test phase to trigger test servers shutdown and save memory at the end of each testsuite module:

mvn -Pfast,wildfly810 post-integration-test

Clean the project:

mvn -Pdist,testsuite clean

Build the WS stack and install it on a specified server instance without running the integration testsuite:

mvn -Pwildfly900 -Dserver.home=/foo/wildfly-9.0.0.Alpha2-SNAPSHOT package

When a server.home option is not provided, the build creates a zip archive with a vanilla WildFly server patched with the current WS stack: the zip file path is modules/dist/target/jbossws-cxf-dist-$\{ project.version} -wildflyXYZ.zip

mvn -Pwildfly810 package

7.4. Container remote debugging

While debugging a testcase is simply a matter of providing the -Ddebug option, remote debugging the container code that runs the WS stack requires few additional setup steps. The suggested approach is to identify a single test to run; before actually running the test, manually start a target container in debug mode and specifying the proper port offset and server configuration (have a look at the arquillian.xml decriptors in the testsuite), then run the tests with -Dserver.home=…​ option pointing to the home dir for the server currently running.

Copyright © 2011 Red Hat, Inc.

The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution—​Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/ . In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.

Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.

Red Hat, Red Hat Enterprise Linux, the Shadowman logo, JBoss, MetaMatrix, Fedora, the Infinity Logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.

Linux® is the registered trademark of Linus Torvalds in the United States and other countries.

Java® is a registered trademark of Oracle and/or its affiliates.

XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.

MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.

Apache, Apache CXF, CXF, Apache WSS4J, WSS4J, Apache Maven, Maven and the Apache feather logo are trademarks of The Apache Software Foundation.

All other trademarks are the property of their respective owners.

         

We use JProfiler for profiling