Chapter 5. Securing the Camel Jetty Component

Abstract

5.1. Enabling SSL/TLS Security

Overview

This section explains how to enable SSL/TLS security on the Apache Camel Jetty component, which is used to create a HTTPS Web server. The key step is to customize the Jetty component by setting the sslSocketConnectorProperties property, which configures SSL/TLS. You must also change the protocol scheme on the Jetty URI from http to https.

Tutorial steps

To configure SSL/TLS security for a Camel Jetty endpoint deployed in the OSGi container, perform the following steps:

Generate a Maven project

The maven-archetype-quickstart archetype creates a generic Maven project, which you can then customize for whatever purpose you like. To generate a Maven project with the coordinates, org.jbossfuse.example:jetty-security, enter the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-quickstart -DgroupId=org.jbossfuse.example -DartifactId=jetty-security
The result of this command is a directory, ProjectDir/jetty-security, containing the files for the generated project.
Note
Be careful not to choose a group ID for your artifact that clashes with the group ID of an existing product! This could lead to clashes between your project's packages and the packages from the existing product (because the group ID is typically used as the root of a project's Java package names).

Customize the POM file

You must customize the POM file in order to generate an OSGi bundle. Follow the POM customization steps described in section "Generating a Bundle Project" in "Deploying into Apache Karaf".
Alternatively, edit the jetty-security/pom.xml file and replace its contents with the following XML code:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.jbossfuse.example</groupId>
  <artifactId>jetty-security</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>bundle</packaging>

  <name>jetty-security</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <defaultGoal>install</defaultGoal>
    <plugins>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.3.7</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>
              ${project.groupId}.${project.artifactId}
            </Bundle-SymbolicName>
            <Import-Package>*</Import-Package>
          </instructions>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Install sample keystore files

In a convenient location, create the clientKeystore.jks key pair and the serviceKeystore.jks key pair using the Java keytool utility, as follows:
keytool -genkeypair -keyalg RSA -dname "CN=Client, OU=Engineering, O=Red Hat, ST=Dublin, C=IE" -validity 365 -alias client -keypass KeyPass -keystore clientKeystore.jks -storepass StorePass

keytool -genkeypair -keyalg RSA -dname "CN=Service, OU=Engineering, O=Red Hat, ST=Dublin, C=IE" -validity 365 -alias service -keypass KeyPass -keystore serviceKeystore.jks -storepass StorePass
Copy the clientKeystore.jks certificate and the serviceKeystore.jks certificate to the EsbInstallDir/etc/certs directory (where you will need to create the etc/certs sub-directory). After copying, you should have the following directory structure under EsbInstallDir/etc/:
EsbInstallDir/etc/
    |
    \--certs/
        |
        \--clientKeystore.jks
           serviceKeystore.jks
Where clientKeystore.jks, and serviceKeystore.jks are the keystores that are used in this demonstration.
Warning
The demonstration key store and trust store are provided for testing purposes only. Do not deploy these certificates in a production system. To set up a genuinely secure SSL/TLS system, you must generate custom certificates, as described in Appendix A, Managing Certificates.

Configure Jetty with SSL/TLS

The Jetty Web server is created by defining a Jetty endpoint at the start of an Apache Camel route. The route is then responsible for processing the incoming HTTP request and generating a reply. The current example simply sends back a small HTML page in the reply. For a more realistic application, you would typically process the incoming message using a bean, which accesses the message through the Java servlet API.
Create the following directory to hold the Spring configuration files:
ProjectDir/jetty-security/src/main/resources/META-INF/spring
In the spring directory that you just created, use your favourite text editor to create the file, jetty-spring.xml, containing the following XML configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.4.0.xsd
       http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">

    <bean id="jetty" class="org.apache.camel.component.jetty9.JettyHttpComponent9">
        <property name="sslContextParameters" ref="sslContextParameters" />
    </bean>

    <sslContextParameters id="sslContextParameters" xmlns="http://camel.apache.org/schema/spring">
        <secureSocketProtocols>
            <!-- Do NOT enable SSLv3 (POODLE vulnerability) -->
            <secureSocketProtocol>TLSv1</secureSocketProtocol>
            <secureSocketProtocol>TLSv1.1</secureSocketProtocol>
            <secureSocketProtocol>TLSv1.2</secureSocketProtocol>
        </secureSocketProtocols>
        <keyManagers keyPassword="KeyPass">
            <keyStore resource="etc/certs/serviceKeystore.jks" password="StorePass"/>
        </keyManagers>
        <trustManagers>
            <keyStore resource="etc/certs/serviceKeystore.jks" password="StorePass"/>
        </trustManagers>
    </sslContextParameters>

    <camelContext trace="true" xmlns="http://camel.apache.org/schema/spring">
        <route>
            <from uri="jetty:https://0.0.0.0:8282/services?matchOnUriPrefix=true"/>
            <transform>
                <constant>&lt;html>&lt;body>Hello from Fuse ESB server&lt;/body>&lt;/html></constant>
            </transform>
        </route>
    </camelContext>

</beans>
The jetty bean defines a new instance of the Apache Camel Jetty component, overriding the default component defined in the camel-jetty JAR file. This Jetty component is configured using the sslContextParameters element, as follows:
secureSocketProtocols
Explicitly lists the SSL/TLS protocols supported by the Jetty server.
Important
This configuration explicitly disables the SSLv3 protocol, in order to safeguard against the Poodle vulnerability (CVE-2014-3566). For more details, see Disabling SSLv3 in JBoss Fuse 6.x and JBoss A-MQ 6.x.
keyManagers/@keyPassword
The password that decrypts the private key stored in the keystore (usually having the same value as password).
keyManagers/keyStore/@resource
The location of the Java keystore file (in JKS format) containing the Jetty server's own X.509 certificate and private key. This location is specified on the filesystem (not on the classpath), relative to the directory where the OSGi container is started.
keyManagers/keyStore/@password
The keystore password that unlocks the keystore.
trustManagers/@resource
The location of the Java keystore file containing one or more trusted certificates (that is, the CA certificates that have been used to sign X.509 certificates from trusted clients). This location is specified on the filesystem (not on the classpath), relative to the directory where the OSGi container is started.
Strictly speaking, this property is not needed, if clients do not send certificates to the Jetty service.
trustManagers/@password
The keystore password that unlocks the truststore trust store.
You must also modify the URI at the start of the route (the uri attribute of the from element). Make sure that the scheme of the URI matches the secure Jetty component, jetty, that you have just created. You must also change the protocol scheme from http to https.
Note
Always double-check you have changed the protocol scheme to https. This is such a small change, it is easy to forget.

Build the bundle

Use Maven to build the bundle. Open a command prompt, switch the current directory to ProjectDir/jetty-security, and enter the following command:
mvn install -Dmaven.test.skip=true
This command builds the bundle and installs it in your local Maven repository.

Install the camel-jetty feature

If you have not already done so, start up the JBoss Fuse console (and container instance) by entering the following command in a new command prompt:
./bin/fuse
The camel-jetty feature, which defines the bundles required for the Camel/Jetty component, is not installed by default. To install the camel-jetty feature, enter the following console command:
JBossFuse:karaf@root> features:install camel-jetty

Deploy the bundle

To deploy and activate the bundle, enter the following console command:
JBossFuse:karaf@root> osgi:install -s mvn:org.jbossfuse.example/jetty-security/1.0-SNAPSHOT
The preceding command loads the bundle from your local Maven repository. You might need to configure the Mvn URL handler with the location of your local Maven repository, if the bundle cannot be found (see section "Mvn URL Handler" in "Deploying into Apache Karaf").

Test the bundle

To test the Jetty service, enter the following curl command at a comand-line prompt:
curl https://localhost:8282/services -k
Note
Don't forget to use https: instead of http: in the URL!
The -k flag allows curl to skip the SSL certificate check (that is, checking that the received server certificate is signed by a local CA certificate), so that the server identity is not verified. You should receive the following HTTP response:
<html><body>Hello from Fuse ESB server</body></html>

Uninstall the bundle

To uninstall the broker bundle, you need to know its bundle ID, BundleID, in which case you can uninstall it by entering the following console command:
JBossFuse:karaf@root> osgi:uninstall BundleID