7.2. Securing the Web Services Proxy

Overview

This section explains how to enable SSL/TLS security on the Camel CXF endpoint, which acts as a proxy for the real Web service. Assuming that you already have the X.509 certificates available, all that is required is to add a block of configuration data to the Spring configuration file (where the configuration data is contained in a httpj:engine-factory element). There is just one slightly subtle aspect to this, however: you need to understand how the Camel CXF endpoint gets associated with the SSL/TLS configuration details.

Implicit configuration

A WS endpoint can be configured by creating the endpoint in Spring and then configuring SSL/TLS properties on its Jetty container. The configuration can be somewhat confusing, however, for the following reason: the Jetty container (which is configured by a httpj:engine-factory element in Spring) does not explicitly reference the WS endpoints it contains and the WS endpoints do not explicitly reference the Jetty container either. The connection between the Jetty container and its contained endpoints is established implicitly, in that they are both configured to use the same TCP port, as illustrated by Figure 7.2, “WS Endpoint Implicitly Configured by httpj:engine-factory Element”.

Figure 7.2. WS Endpoint Implicitly Configured by httpj:engine-factory Element

WS Endpoint Implicitly Configured by httpj:engine-factory Element
The connection between the Web service endpoint and the httpj:engine-factory element is established as follows:
  1. The Spring container loads and parses the file containing the httpj:engine-factory element.
  2. When the httpj:engine-factory bean is created, a corresponding entry is created in the registry, storing a reference to the bean. The httpj:engine-factory bean is also used to initialize a Jetty container that listens on the specified TCP port.
  3. When the WS endpoint is created, it scans the registry to see if it can find a httpj:engine-factory bean with the same TCP port as the TCP port in the endpoint's address URL.
  4. If one of the beans matches the endpoint's TCP port, the WS endpoint installs itself into the corresponding Jetty container. If the Jetty container has SSL/TLS enabled, the WS endpoint shares those security settings.

Steps to add SSL/TLS security to the Jetty container

To add SSL/TLS security to the Jetty container, thereby securing the WS proxy endpoint, perform the following steps:

Add certificates to the bundle resources

The certificates used in this demonstration are taken from a sample in the Apache CXF 3.1.5.redhat-630187 product. If you install the standalone version of Apache CXF (available in the InstallDir/extras/ directory), you will find the sample certificates in the CXFInstallDir/samples/wsdl_first_https/src/main/config directory.
Copy the clientKeystore.jks and serviceKeystore.jks keystores from the CXFInstallDir/samples/wsdl_first_https/src/main/config directory to the CamelInstallDir/examples/camel-example-cxf-proxy/src/main/resources/certs directory (you must first create the certs sub-directory).

Modify POM to switch off resource filtering

Including the certificates directly in the bundle as resource is the most convenient way to deploy them. But when you deploy certificates as resources in a Maven project, you must remember to disable Maven resource filtering, which corrupts binary files.
To disable filtering of .jks files in Maven, open the project POM file, CamelInstallDir/examples/camel-example-cxf-proxy/pom.xml, with a text editor and add the following resources element as a child of the build element:
<?xml version="1.0" encoding="UTF-8"?>
...
<project ...>
  ...
  <build>
    <plugins>
      ...
    </plugins>

    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
        <excludes>
          <exclude>**/*.jks</exclude>
        </excludes>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>false</filtering>
        <includes>
          <include>**/*.jks</include>
        </includes>
      </resource>
    </resources>
  </build>

</project>

Instantiate the CXF Bus

You should instantiate the CXF bus explicitly in the Spring XML (this ensures that it will be available to the Jetty container, which is instantiated by the httpj:engine-factory element in the next step). Edit the camel-config.xml file in the src/main/resources/META-INF/spring directory, adding the cxfcore:bus element as a child of the beans element, as follows:
<beans ... >
    ...
 <cxfcore:bus/>
    ...
</beans>
Note
The cxfcore: namespace prefix will be defined in a later step.

Add the httpj:engine-factory element to Spring configuration

To configure the Jetty container that listens on TCP port 9080 to use SSL/TLS security, edit the camel-config.xml file in the src/main/resources/META-INF/spring directory, adding the httpj:engine-factory element as shown in Example 7.2, “httpj:engine-factory Element with SSL/TLS Enabled”.
In this example, the required attribute of the sec:clientAuthentication element is set to false, which means that a connecting client is not required to present an X.509 certificate to the server during the SSL/TLS handshake (although it may do so, if it has such a certificate).

Example 7.2. httpj:engine-factory Element with SSL/TLS Enabled

<beans ... >
    ...
    <httpj:engine-factory bus="cxf">
      <httpj:engine port="${proxy.port}">
        <httpj:tlsServerParameters secureSocketProtocol="TLSv1">
          <sec:keyManagers keyPassword="skpass">
            <sec:keyStore resource="certs/serviceKeystore.jks" password="sspass" type="JKS"/>
          </sec:keyManagers>
          <sec:trustManagers>
            <sec:keyStore resource="certs/serviceKeystore.jks" password="sspass" type="JKS"/>
          </sec:trustManagers>
          <sec:cipherSuitesFilter>
            <sec:include>.*_WITH_3DES_.*</sec:include>
            <sec:include>.*_WITH_DES_.*</sec:include>
            <sec:exclude>.*_WITH_NULL_.*</sec:exclude>
            <sec:exclude>.*_DH_anon_.*</sec:exclude>
          </sec:cipherSuitesFilter>
          <sec:clientAuthentication want="true" required="false"/>
        </httpj:tlsServerParameters>
      </httpj:engine>
    </httpj:engine-factory>

</beans>
Important
You must set secureSocketProtocol to TLSv1 on the server side, in order to protect against the Poodle vulnerability (CVE-2014-3566)

Define the cxfcore:, sec: and httpj: prefixes

Define the cxfcore:, sec: and httpj: namespace prefixes, which appear in the definitions of the cxfcore:bus element and the httpj:engine-factory element, by adding the following highlighted lines to the beans element in the camel-config.xml file:
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:camel="http://camel.apache.org/schema/spring"
       xmlns:cxf="http://camel.apache.org/schema/cxf"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cxfcore="http://cxf.apache.org/core"
       xmlns:sec="http://cxf.apache.org/configuration/security"
       xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
       http://camel.apache.org/schema/cxf http://camel.apache.org/schema/cxf/camel-cxf.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
       http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
       http://cxf.apache.org/transports/http-jetty/configuration http://cxf.apache.org/schemas/configuration/http-jetty.xsd
       ">
Note
It is essential to specify the locations of the http://cxf.apache.org/configuration/security schema and the http://cxf.apache.org/transports/http-jetty/configuration schema in the xsi:schemaLocation attribute. These will not automatically be provided by the OSGi container.

Modify proxy address URL to use HTTPS

The proxy endpoint at the start of the Apache Camel route is configured by the cxf:cxfEndpoint element in the camel-config.xml file. By default, this proxy endpoint is configured to use the HTTP protocol. You must modify the address URL to use the secure HTTPS protocol instead, however. In the camel-config.xml file, edit the address attribute of the cxf:cxfEndpoint element, replacing the http: prefix by the https: prefix, as shown in the following fragment:
<beans ...>
    ...
    <cxf:cxfEndpoint id="reportIncident"
                     address="https://localhost:${proxy.port}/camel-example-cxf-proxy/webservices/incident"
                     endpointName="s:ReportIncidentEndpoint"
                     serviceName="s:ReportIncidentEndpointService"
                     wsdlURL="etc/report_incident.wsdl"
                     xmlns:s="http://reportincident.example.camel.apache.org"/>
    ...
</beans>
Notice also that the address URL is configured to use the TCP port, ${proxy.port} (which has the value 9080 by default). This TCP port value is the same as the value set for the Jetty container (configured by the http:engine-factory element), thus ensuring that this endpoint is deployed into the Jetty container. The attributes of the cxf:cxfEndpoint specify the WSDL addressing details as described in the section called “WSDL addressing details”:
serviceName
Specifies the WSDL service name.
endpointName
Specifies the WSDL port name.
address
Specifies the address URL of the proxy Web service.