Camel's XML Security Component is used when you need to encrypt and decrypt all or parts of an XML message. A Data Format provided by this component handles transformation between an encrypted and decrypted message.
The XML Security Component supports both symmetric and asymmetric encryption of XML messages as outlined by the W3C Recommendation XML Encryption Syntax and Processing. In symmetric encryption, a password shared by the sender and receiver is used to encrypt and decrypt a message. Using asymmetric encryption, the public key of the message recipient is used to encrypt the message, thereby only permitting the intended recipient to decrypt it.
This Camel component allows you to provide an XPath that points to a node, or set of nodes, in the document that will be encrypted; if none is provided the entire document will be encrypted.
This recipe will show you how to configure full asymmetric encryption of XML message payloads. It will show you how to encrypt and decrypt a fragment of an XML message by providing an XPath to the node to be encrypted.
The Java code for this recipe is located in the org.camelcookbook.transformation.xmlsecurity
package. The Spring XML files are located under src/main/resources/META-INF/spring
and prefixed with xmlsecurity
.
To use Camel's XML Security Component, you need to add a dependency on the Camel XML Security Component that provides an implementation for the XML Security Data Format using the Apache XML Security (Santuario) library.
Add the following to the dependencies
section of your Maven POM:
<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-xmlsecurity</artifactId> <version>${camel-version}</version> </dependency>
Before using the cryptographic capabilities available in Camel to encrypt and decrypt fragments of an XML message you will need:
For the purposes of this example we will use the keytool
utility that is included as part of the Java Development Kit (JDK) to generate these keys and place them into the appropriate stores:
# keytool -genkeypair -v -keyalg RSA -alias system_a -keystore xml_keystore.jks -dname 'CN=Scott,O=camelcookbook.org'-storepass keystorePassword -validity 3650 -keypass keyPasswordA
# keytool -export -alias system_a -keystore xml_keystore.jks -rfc -file selfsignedcert_xml_a.cer -storepass keystorePassword
# keytool -import -noprompt -alias system_a -file selfsignedcert_xml_a.cer -keystore xml_truststore.jks -storepass truststorePassword
To encrypt, and subsequently decrypt an XML fragment in a document on the exchange, perform the following steps:
If using Spring, define a keyStoreParameters
tag outside of the camelContext
element:
<beans ... xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation="... http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camel:keyStoreParameters id="trustStoreParams" resource="xml_truststore.jks" password="truststorePassword"/> <camelContext ...> </beans>
The resource
setting is a Camel resource path, so in this example it will look on the classpath for xml_truststore.jks
. To find a truststore on the filesystem or on an HTTP server, you prefix the location with file:
or http:
respectively.
If using Java, add the following code inside the configure()
method of your RouteBuilder
implementation:
KeyStoreParameters trustStoreParameters = new KeyStoreParameters(); trustStoreParameters.setResource("xml_truststore.jks"); trustStoreParameters.setPassword("truststorePassword");
secureXML
data format to marshal the unencrypted XML body of the exchange. This will perform the encryption step.Using the XML DSL, this is done as follows:
<from uri="direct:encrypt"/>
<marshal>
<secureXML
secureTag="/booksignings/store/address"
secureTagContents="true"
recipientKeyAlias="system_a"
xmlCipherAlgorithm=
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
keyCipherAlgorithm=
"http://www.w3.org/2001/04/xmlenc#rsa-1_5"
keyOrTrustStoreParametersId="trustStoreParams"/>
</marshal>
<to uri="direct:decrypt"/>
The secureTag
attribute contains the XPath of the message fragment to encrypt (use an empty String for the entire document).
The xmlCipherAlgorithm
is a reference to the algorithm used to encrypt the XML.
The keyCipherAlgorithm
is the algorithm that was used when the keys were generated in the Getting ready section of this recipe (RSA).
The same route is expressed in the Java DSL as follows:
from("direct:encrypt")
.marshal()
.secureXML(
"/booksignings/store/address", // secure tag
true, // secure tag contents
"system_a", // recipient key alias
XMLCipher.TRIPLEDES, // xml cipher
XMLCipher.RSA_v1dot5, // key cipher
trustStoreParameters)
.to("mock:marshalResult");
If using Spring, again define a keyStoreParameters
tag outside of the camelContext
element:
<beans ... xmlns:camel="http://camel.apache.org/schema/spring" xsi:schemaLocation="... http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd"> <camel:keyStoreParameters id="keyStoreParams" resource="xml_keystore.jks" password="keystorePassword"/> <camelContext ...> </beans>
If using Java, add the following code inside the configure()
method of your RouteBuilder
implementation:
KeyStoreParameters keyStoreParameters = new KeyStoreParameters(); keyStoreParameters.setResource("xml_keystore.jks"); keyStoreParameters.setPassword("keystorePassword");
secureXML
data format to unmarshal the encrypted XML body of the exchange. This will perform the decryption step. Using the XML DSL this is done as follows:
<from uri="direct:decrypt"/> <unmarshal> <secureXML secureTag="/booksignings/store/address" secureTagContents="true" recipientKeyAlias="system_a" xmlCipherAlgorithm= "http://www.w3.org/2001/04/xmlenc#tripledes-cbc" keyCipherAlgorithm= "http://www.w3.org/2001/04/xmlenc#rsa-1_5" keyOrTrustStoreParametersId="keyStoreParams" keyPassword="keyPasswordA"/> </unmarshal> <to uri="mock:out"/>
The same route is expressed in the Java DSL as follows:
from("direct:decrypt") .unmarshal() .secureXML( "/booksignings/store/address", // secure tag true, // secure tag contents "system_a", // recipient key alias XMLCipher.TRIPLEDES, // xml cipher XMLCipher.RSA_v1dot5, // key cipher keyStoreParameters, "keyPasswordA") // key password .to("mock:out");
The XML Security Component uses the Apache Santuario library to perform the XML encryption operations.
Given the following payload:
<booksignings> <store> <address> <street>123 Main St</street> <city>Boston</city> </address> <authors> <author>Scott Cranton</author> </authors> </store> <!-- … --> </booksignings>
The encrypted version will appear as:
<booksignings> <store> <address> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content"> <xenc:EncryptionMethod Algorithm= "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"/> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <xenc:EncryptedKey> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#kw-tripledes"/> <xenc:CipherData> <xenc:CipherValue> i19aQxl9a5QV7cVym/5gV9Ih67Jklt6oc3Aph2ec6/zpui+0MC8YJw== </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedKey> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue> RvUlpr8CN51DcUx+Y3C7msQoprtoqc5vx9CplhmBqstZGHj5ThVuvJArFMaVXloXZs6cd7w4N1bF/9E1Xa85CAB7uYwKwSFjzRgigndEXV4= </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </address> <authors> <author>Scott Cranton</author> </authors> </store> <!-- ... --> </booksignings>
This use of message encryption allows you to create routes that can encrypt sensitive information early within your message processing. All subsequent downstream message-processing steps will only have access to the encrypted contents. Through the use of partial message encryption, you can ensure that the most sensitive parts are hidden while still allowing content based routing and other message processing operations based on the non-sensitive parts of the message.
The XML Security Component also easily handles documents containing XML namespaces. Consider the following payload:
<?xml version="1.0" encoding="UTF-8"?> <booksignings xmlns="http://camelcookbook.org/schema/booksignings"> <store> <address> <street>123 Main St</street> <city>Boston</city> </address> <authors> <author>Scott Cranton</author> </authors> </store> <!-- ... --> </booksignings>
To encrypt this message using the XML DSL, you define an XML namespace on the camelContext
element:
<camelContext xmlns="http://camel.apache.org/schema/spring" xmlns:c="http://camelcookbook.org/schema/booksignings">
You can then use the c:
namespace in your XPath Expression:
<secureXML
secureTag="/c:booksignings/c:store/c:address"
secureTagContents="true"
recipientKeyAlias="system_a"
xmlCipherAlgorithm=
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
keyCipherAlgorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"
keyOrTrustStoreParametersId="trustStoreParams"/>
To encrypt the message using the Java DSL, you define a Map
of prefixes to namespace URIs inside your RouteBuilder
implementation:
Map<String, String> namespaces = new HashMap<String, String>(); namespaces.put("c","http://camelcookbook.org/schema/booksignings");
You then provide Map
as an additional argument to the secureXML
DSL statement. This allows you to use the c:
namespace prefix in your XPath Expression to identify the node to be encrypted.
.secureXML( "/c:booksignings/c:store/c:address", // prefixed XPath namespaces, true, // secure tag contents "system_a", // recipient key alias XMLCipher.TRIPLEDES, // xml cipher XMLCipher.RSA_v1dot5, // key cipher trustStoreParameters)
3.137.212.212