Red Hat Training

A Red Hat training course is available for Red Hat Fuse

Chapter 4. WS-Security

4.1. WS-Security Overview

WS-Security standards allow policies to be applied to SOA for controlled service usage and monitoring. 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 these basics to really 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. 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. 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.

4.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. 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.

4.3. Apache CXF WS-Security Implementation

Apache CXF features a WS-Security module that supports multiple configurations and is easily extendible. 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. For more details, refer to the Apache CXF documentation.
Recent versions of Apache CXF 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 or installing the required interceptors. The Apache CXF WS-Policy engine internally takes care of that.

4.3.1. 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 and operations reference WS-Policy fragments with the security requirements to interact with the service. The WS-SecurityPolicy specification allows for specifying things like asymmetric and symmetric keys, using transports (https) for encryption, which parts or headers to encrypt or sign, whether to sign then encrypt or encrypt then sign, whether to include timestamps, and whether to use derived keys.
Some mandatory configuration elements are not covered by WS-SecurityPolicy because they are not meant to be public or part of the published endpoint contract. These include things such as keystore locations, usernames and passwords. Apache CXF allows configuring these elements either through Spring xml descriptors or using the client API or annotations. Below is the list of supported configuration properties:

Table 4.1. Supported Configuration Properties

Property Description
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 is called.
ws-security.callback-handler
The WSS4J security CallbackHandler that is used to retrieve passwords for keystores and UsernameTokens.
ws-security.signature.properties
The properties file or object that contains the WSS4J properties for configuring the signature keystore and crypto objects.
ws-security.encryption.properties
The properties file or 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. If not specified, it uses the default alias set in the properties file. If that is also not set, and the keystore only contains a single key, that key is used.
ws-security.encryption.username
The username or alias for the key in the encryption keystore. If not specified, it uses the default alias set in the properties file. If that is also not set, and the keystore only contains a single key, that key is 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.
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");	

For additional configuration details, refer to the Apache CXF documentation.

4.3.2. 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. 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: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>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 javax.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!";
   }
}

4.3.3. 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 {
   ...
}

4.4. Enable WS-Security

Procedure 4.1. Enable WS-Security

  1. Define a Policy within your WSDL and reference it with a PolicyReference inside your binding.
  2. Configure your <soap.binding> with <securityAction>.
    This is so that JBossWS-CXF knows which tokens to respect within incoming SOAP requests.
  3. Include a WEB-INF/jboss-web.xml file in your application with a <security-domain> specified.
    This is so that JBossWS-CXF knows which modules to use for authentication and rolemapping.

4.5. Sample WS-Security Configurations

JBoss Fuse Service Works provides the policy-security-wss-username quickstart application as an example. The following are the pertinent sections:
  • META-INF/WorkService.wsdl:
    <binding name="WorkServiceBinding" type="tns:WorkService">
      <wsp:PolicyReference URI="#WorkServicePolicy"/>
      ...
    </binding>
    <wsp:Policy wsu:Id="WorkServicePolicy">
      <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>
  • META-INF/switchyard.xml:
    <binding.soap xmlns="urn:switchyard-component-soap:config:1.0">
      <wsdl>META-INF/WorkService.wsdl</wsdl>
      <contextPath>policy-security-wss-username</contextPath>
      <endpointConfig configFile="META-INF/jaxws-endpoint-config.xml" configName="SwitchYard-Endpoint-Config"/>
      <inInterceptors>
        <interceptor class="org.jboss.wsf.stack.cxf.security.authentication.SubjectCreatingPolicyInterceptor"/>
      </inInterceptors>
    </binding.soap>
  • META-INF/jaxws-endpoint-config.xml:
    <jaxws-config xmlns="urn:jboss:jbossws-jaxws-config:4.0" xmlns:javaee="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:jboss:jbossws-jaxws-config:4.0 schema/jbossws-jaxws-config_4_0.xsd">
      <endpoint-config>
        <config-name>SwitchYard-Endpoint-Config</config-name>
        <property>
            <property-name>ws-security.validate.token</property-name>
            <property-value>false</property-value>
        </property>
      </endpoint-config>
    </jaxws-config>
  • WEB-INF/jboss-web.xml:
    <jboss-web>
        <security-domain>java:/jaas/other</security-domain>
    </jboss-web>
With these in place, JBossWS-CXF intercepts incoming SOAP requests, extract the UsernameToken, attempt to authenticate it against the LoginModule(s) configured in the application server's "other" security domain, and provide any authorized roles. If successful, the request is handed over to SwitchYard, which processes it further, including enforcing your own policies. In the case of WS-Security, SwitchYard does not attempt a second clientAuthentication, but instead respects the outcome from JBossWS-CXF.

Note

If the original clientAuthentication fails, this is a "fail-fast" scenario, and the request is not channeled into SwitchYard.

4.6. Signature and Encryption Support

To add the support for WS-Security Signature and Encryption, ensure the following:

4.7. Sample Endpoint Configurations

An endpoint declares all the abstract methods that are exposed to the client. You can use endpoint configurations to include property declarations. The endpoint implementations can be associated with a given endpoint configuration using the @EndpointConfig annotation. The following steps describe a sample endpoint configuration:
  1. Create the web service endpoint using JAX-WS. 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:
    
    <?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-cxf:Basic128GCM xmlns:sp-cxf="http://cxf.apache.org/custom/security-policy"/>
                  </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>
    
    You can generate the service endpoint using the wsconsume tool and then use a @EndpointConfig annotation as shown below:
    
    package org.jboss.test.ws.jaxws.samples.wsse.policy.basic;
     
    import javax.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!";
       }
    }
    
  2. Use the referenced jaxws-endpoint-config.xml descriptor to provide a custom endpoint configuration with the required server side configuration properties as shown below. This tells the engine which certificate or key to use for signature, signature verification, encryption, and decryption.
    
    <?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>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>
    
    Here,
    • The bob.properties configuration file includes the WSS4J Crypto properties which in turn links to the keystore file, type, alias, and password for accessing it. For example:
      
      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
      
    • The callback handler enables Apache CXF to access the keystore. For example:
      
      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);
         }
      }
      
  3. Assuming the bob.jks keystore is properly generated and contains the server Bob's full key as well as the client Alice's public key, you can proceed to packaging the endpoint. Here is the expected content:
     /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
    Here, the jaxws classes generated by the tools and a basic web.xml referencing the endpoint bean are also included:
    
    <?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>
    

    Note

    If you are deploying the endpoint archive to JBoss Application Server 7, 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

4.8. Sample Client Configurations

On the client side, use the wsconsume tool to consume the published WSDL and then invoke the endpoint as a standard JAX-WS one as shown below:

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 same as that on the server side. The alice.properties file is the client side equivalent of the server side bob.properties file and references the alice.jks keystore file, which has been populated with client Alice's full key as well as server Bob's 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 consumes the security requirements in the contract and ensures that a valid secure communication is in place for interacting with the server endpoint.

4.9. Endpoint Serving Multiple Clients

n the endpoint and client configuration examples, the server side configuration implies that the endpoint is configured for serving a given client which a service agreement is established for. In real world scenarios, a server should be able to decrypt and encrypt 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. The referenced server side keystore then needs to contain the public key of all the clients that are expected to be served.

4.10. Sample CXF Interceptor Configurations

For adding a CXF Interceptor, perform the following configuration settings:
  • META-INF/switchyard.xml
    
    <binding.soap xmlns="urn:switchyard-component-soap:config:1.0">
      <wsdl>META-INF/WorkService.wsdl</wsdl>
      <contextPath>policy-security-wss-username</contextPath>
      <inInterceptors>
        <interceptor class="com.example.MyInterceptor"/>
      </inInterceptors>
    </binding.soap>
    
  • com/example/MyInterceptor.java
    
    public class MyInterceptor extends WSS4JInterceptor {
      private static final PROPS;
      static {
        Map<String,String> props = new HashMap<String,String>();
        props.put("action", "Signature Encryption");
        props.put("signaturePropFile", "META-INF/bob.properties");
        props.put("decryptionPropFile", "META-INF/bob.properties");
        props.put("passwordCallbackClass", "com.example.MyCallbackHandler");
        PROPS = props;
      }
      public MyInterceptor() {
        super(PROPS);
      }
    }
    
  • META-INF/bob.properties
    
    org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
    org.apache.ws.security.crypto.merlin.keystore.type=jks
    org.apache.ws.security.crypto.merlin.keystore.password=password
    org.apache.ws.security.crypto.merlin.keystore.alias=bob
    org.apache.ws.security.crypto.merlin.file=META-INF/bob.jks