You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ha...@apache.org on 2011/06/21 04:42:46 UTC
svn commit: r1137849 - in /camel/branches/camel-2.7.x: ./
components/camel-http/
components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/
components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/
com...
Author: hadrian
Date: Tue Jun 21 02:42:46 2011
New Revision: 1137849
URL: http://svn.apache.org/viewvc?rev=1137849&view=rev
Log:
CAMEL-4061. Port to the 2.7.x branch
Added:
camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/recipient.ks
- copied unchanged from r1135364, camel/trunk/components/camel-xmlsecurity/src/test/resources/recipient.ks
camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/sender.ts
- copied unchanged from r1135364, camel/trunk/components/camel-xmlsecurity/src/test/resources/sender.ts
Modified:
camel/branches/camel-2.7.x/ (props changed)
camel/branches/camel-2.7.x/components/camel-http/ (props changed)
camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/log4j.properties
Propchange: camel/branches/camel-2.7.x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jun 21 02:42:46 2011
@@ -1 +1 @@
-/camel/trunk:1083696,1087276,1087612,1087856,1088583,1088916-1088917,1089275,1090166,1091518,1091771,1091799,1092068,1092577,1092667,1093978,1095405,1095469,1095471,1095475-1095476,1099417,1102162,1104076,1124497,1131411,1134501
+/camel/trunk:1083696,1087276,1087612,1087856,1088583,1088916-1088917,1089275,1090166,1091518,1091771,1091799,1092068,1092577,1092667,1093978,1095405,1095469,1095471,1095475-1095476,1099417,1102162,1104076,1124497,1131411,1134501,1135364
Propchange: camel/branches/camel-2.7.x/components/camel-http/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Jun 21 02:42:46 2011
@@ -1 +1 @@
-/camel/trunk/components/camel-http:917526,1083696,1087276,1087612,1087856,1088583,1088916-1088917,1089275,1090166,1091518,1091771,1091799,1092068,1092577,1092667,1093978,1095405,1095469,1095471,1095475-1095476,1099417,1102162,1104076,1124497,1131411,1134501
+/camel/trunk/components/camel-http:917526,1083696,1087276,1087612,1087856,1088583,1088916-1088917,1089275,1090166,1091518,1091771,1091799,1092068,1092577,1092667,1093978,1095405,1095469,1095471,1095475-1095476,1099417,1102162,1104076,1124497,1131411,1134501,1135364
Modified: camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java?rev=1137849&r1=1137848&r2=1137849&view=diff
==============================================================================
--- camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java (original)
+++ camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java Tue Jun 21 02:42:46 2011
@@ -19,11 +19,18 @@ package org.apache.camel.dataformat.xmls
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.URL;
import java.security.InvalidKeyException;
import java.security.Key;
+import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
+import java.util.Map;
+
+import javax.crypto.KeyGenerator;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.SecretKeySpec;
@@ -32,8 +39,11 @@ import javax.xml.transform.dom.DOMSource
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
import org.w3c.dom.traversal.NodeIterator;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.util.ExchangeHelper;
@@ -45,11 +55,31 @@ import org.apache.xml.security.encryptio
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xpath.XPathAPI;
-public class XMLSecurityDataFormat implements DataFormat {
+public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
+
+ public static final String XML_ENC_RECIPIENT_ALIAS = "CamelXmlEncryptionRecipientAlias";
+ public static final String XML_ENC_TRUST_STORE_URL = "CamelXmlEncryptionTrustStoreUrl";
+ public static final String XML_ENC_TRUST_STORE_PASSWORD = "CamelXmlEncryptionTrustStorePassword";
+ public static final String XML_ENC_KEY_STORE_URL = "CamelXmlEncryptionKeyStoreUrl";
+ public static final String XML_ENC_KEY_STORE_PASSWORD = "CamelXmlEncryptionKeyStorePassword";
+ public static final String XML_ENC_KEY_STORE_ALIAS = "CamelXmlEncryptionKeyAlias";
+
private String xmlCipherAlgorithm;
+ private String keyCipherAlgorithm;
private byte[] passPhrase;
+
private String secureTag;
private boolean secureTagContents;
+
+ private KeyStore keyStore;
+ private KeyStore trustStore;
+ private String keyStoreAlias;
+ private String keyStorePassword;
+ private String trustStorePassword;
+ private String recipientKeyAlias;
+
+ private CamelContext camelContext;
+
public XMLSecurityDataFormat() {
this.xmlCipherAlgorithm = XMLCipher.TRIPLEDES;
@@ -73,45 +103,197 @@ public class XMLSecurityDataFormat imple
this.setPassPhrase(passPhrase);
}
- public XMLSecurityDataFormat(String secureTag, boolean secureTagContents, byte[] passPhrase, String xmlCipherAlgorithm) {
+ public XMLSecurityDataFormat(String secureTag, boolean secureTagContents, byte[] passPhrase,
+ String xmlCipherAlgorithm) {
this();
this.setSecureTag(secureTag);
this.setSecureTagContents(secureTagContents);
this.setPassPhrase(passPhrase);
this.setXmlCipherAlgorithm(xmlCipherAlgorithm);
}
+
+ public XMLSecurityDataFormat(String secureTag, boolean secureTagContents, String xmlCipherAlgorithm,
+ String keyCipherAlgorithm) {
+ this();
+ this.setSecureTag(secureTag);
+ this.setSecureTagContents(secureTagContents);
+ this.setXmlCipherAlgorithm(xmlCipherAlgorithm);
+ this.setKeyCipherAlgorithm(keyCipherAlgorithm);
+ }
+
+ public XMLSecurityDataFormat(String secureTag, boolean secureTagContents, String recipientKeyAlias,
+ String xmlCipherAlgorithm, String keyCipherAlgorithm) {
+ this();
+ this.setSecureTag(secureTag);
+ this.setSecureTagContents(secureTagContents);
+ this.setXmlCipherAlgorithm(xmlCipherAlgorithm);
+ this.setRecipientKeyAlias(recipientKeyAlias);
+ this.setKeyCipherAlgorithm(keyCipherAlgorithm);
+ }
+
+ @Override
+ public void setCamelContext(CamelContext camelContext) {
+ try {
+ setDefaultsFromContext(camelContext);
+ } catch (Exception e) {
+ throw new IllegalStateException("Could not initialize XMLSecurityDataFormat with camelContext. ", e);
+ }
+ }
+ @Override
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ /**
+ * Sets missing properties that are defined in the Camel context.
+ */
+ private void setDefaultsFromContext(CamelContext context) throws Exception {
+ Map<String, String> contextProps = context.getProperties();
+
+ if (this.recipientKeyAlias == null) {
+ recipientKeyAlias = contextProps.get(XML_ENC_RECIPIENT_ALIAS);
+ }
+
+ if (this.trustStore == null && contextProps.containsKey(XML_ENC_TRUST_STORE_URL)) {
+ trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ URL trustStoreUrl = new URL(contextProps.get(XML_ENC_TRUST_STORE_URL));
+ if (trustStorePassword == null) {
+ trustStorePassword = contextProps.get(XML_ENC_TRUST_STORE_PASSWORD);
+ }
+ trustStore.load(trustStoreUrl.openStream(), trustStorePassword.toCharArray());
+ }
+
+ if (this.keyStore == null && contextProps.containsKey(XML_ENC_KEY_STORE_URL)) {
+ keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ URL keyStoreUrl = new URL(contextProps.get(XML_ENC_KEY_STORE_URL));
+ if (keyStorePassword == null) {
+ keyStorePassword = contextProps.get(XML_ENC_KEY_STORE_PASSWORD);
+ }
+ keyStore.load(keyStoreUrl.openStream(), keyStorePassword.toCharArray());
+ }
+
+ if (this.keyStoreAlias == null) {
+ keyStoreAlias = contextProps.get(XML_ENC_KEY_STORE_ALIAS);
+ }
+ }
+
public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
-
// Retrieve the message body as input stream
InputStream is = exchange.getContext().getTypeConverter().mandatoryConvertTo(InputStream.class, graph);
// and covert that to XML
Document document = exchange.getContext().getTypeConverter().convertTo(Document.class, exchange, is);
+
+ if (null != keyCipherAlgorithm
+ && (keyCipherAlgorithm.equals(XMLCipher.RSA_v1dot5) || keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP))) {
+ encryptAsymmetric(exchange, document, stream);
+ } else if (null != recipientKeyAlias) {
+ encryptAsymmetric(exchange, document, stream);
+ } else {
+ encryptSymmetric(exchange, document, stream);
+ }
+ }
+
+ /**
+ * Configure the public key for the asymmetric key wrap algorithm, create the key cipher, and delegate
+ * to common encryption method.
+ *
+ * The method first checks the exchange for a declared key alias, and will fall back to the
+ * statically-defined instance variable if no value is found in the exchange. This allows different
+ * aliases / keys to be used for multiple-recipient messaging integration patterns such as CBR
+ * or recipient list.
+ */
+ private void encryptAsymmetric(Exchange exchange, Document document, OutputStream stream) throws Exception {
+ String exchangeRecipientAlias = getRecipientKeyAlias(exchange);
+
+ if (null == exchangeRecipientAlias) {
+ throw new IllegalStateException("The recipient's key alias must be defined for asymmetric key encryption.");
+ }
- Key keyEncryptionkey;
- Key dataEncryptionkey;
+ if (null == trustStore) {
+ throw new IllegalStateException("A trust store must be defined for asymmetric key encryption.");
+ }
+
+ Key keyEncryptionKey = getPublicKey(this.trustStore, exchangeRecipientAlias, this.trustStorePassword);
+
+ if (null == keyEncryptionKey) {
+ throw new IllegalStateException("No key for the alias [ " + exchangeRecipientAlias
+ + " ] exists in " + "the configured trust store.");
+ }
+
+ Key dataEncryptionKey = generateDataEncryptionKey();
+
+ XMLCipher keyCipher;
+ if (null != this.getKeyCyperAlgorithm()) {
+ keyCipher = XMLCipher.getInstance(this.getKeyCyperAlgorithm());
+ } else {
+ keyCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5);
+ }
+ keyCipher.init(XMLCipher.WRAP_MODE, keyEncryptionKey);
+ encrypt(exchange, document, stream, dataEncryptionKey, keyCipher);
+ }
+
+ private void encryptSymmetric(Exchange exchange, Document document, OutputStream stream) throws Exception {
+ Key keyEncryptionKey;
+ Key dataEncryptionKey;
if (xmlCipherAlgorithm.equals(XMLCipher.TRIPLEDES)) {
- keyEncryptionkey = generateEncryptionKey("DESede");
- dataEncryptionkey = generateEncryptionKey("DESede");
+ keyEncryptionKey = generateKeyEncryptionKey("DESede");
+ dataEncryptionKey = generateDataEncryptionKey();
} else {
- keyEncryptionkey = generateEncryptionKey("AES");
- dataEncryptionkey = generateEncryptionKey("AES");
+ keyEncryptionKey = generateKeyEncryptionKey("AES");
+ dataEncryptionKey = generateDataEncryptionKey();
}
-
+
XMLCipher keyCipher = XMLCipher.getInstance(generateXmlCipherAlgorithmKeyWrap());
- keyCipher.init(XMLCipher.WRAP_MODE, keyEncryptionkey);
-
+ keyCipher.init(XMLCipher.WRAP_MODE, keyEncryptionKey);
+
+ encrypt(exchange, document, stream, dataEncryptionKey, keyCipher);
+ }
+
+
+ /**
+ * Returns the private key for the specified alias, or null if the alias or private key is not found.
+ */
+ // TODO Move this to a crypto utility class
+ private Key getPrivateKey(KeyStore keystore, String alias, String password) throws Exception {
+ Key key = keystore.getKey(alias, password.toCharArray());
+ if (key instanceof PrivateKey) {
+ return key;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the public key for the specified alias, or null if the alias or private key is not found.
+ */
+ // TODO Move this to a crypto utility class
+ private Key getPublicKey(KeyStore keystore, String alias, String password) throws Exception {
+ Key key = keystore.getKey(alias, password.toCharArray());
+ if (key instanceof PublicKey) {
+ return key;
+ } else {
+ java.security.cert.Certificate cert = keystore.getCertificate(alias);
+ // Get public key
+ PublicKey publicKey = cert.getPublicKey();
+ return publicKey;
+ }
+ }
+
+
+ private void encrypt(Exchange exchange, Document document, OutputStream stream, Key dataEncryptionKey,
+ XMLCipher keyCipher) throws Exception {
XMLCipher xmlCipher = XMLCipher.getInstance(xmlCipherAlgorithm);
- xmlCipher.init(XMLCipher.ENCRYPT_MODE, dataEncryptionkey);
+ xmlCipher.init(XMLCipher.ENCRYPT_MODE, dataEncryptionKey);
if (secureTag.equalsIgnoreCase("")) {
- embedKeyInfoInEncryptedData(document, keyCipher, xmlCipher, dataEncryptionkey);
+ embedKeyInfoInEncryptedData(document, keyCipher, xmlCipher, dataEncryptionKey);
document = xmlCipher.doFinal(document, document.getDocumentElement());
} else {
NodeIterator iter = XPathAPI.selectNodeIterator(document, secureTag);
Node node;
while ((node = iter.nextNode()) != null) {
- embedKeyInfoInEncryptedData(document, keyCipher, xmlCipher, dataEncryptionkey);
+ embedKeyInfoInEncryptedData(document, keyCipher, xmlCipher, dataEncryptionKey);
Document temp = xmlCipher.doFinal(document, (Element) node, getSecureTagContents());
document.importNode(temp.getDocumentElement().cloneNode(true), true);
}
@@ -124,37 +306,74 @@ public class XMLSecurityDataFormat imple
} finally {
stream.close();
}
-
}
-
- public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+
+ public Object unmarshal(Exchange exchange, Document document) throws Exception {
InputStream is = ExchangeHelper.getMandatoryInBody(exchange, InputStream.class);
-
- Key keyEncryptionkey;
+ return unmarshal(exchange, is);
+ }
+
+
+ @Override
+ public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
+ Document encodedDocument = exchange.getContext().getTypeConverter().convertTo(Document.class, exchange, stream);
+
+ if (null != keyCipherAlgorithm
+ && (keyCipherAlgorithm.equals(XMLCipher.RSA_v1dot5) || keyCipherAlgorithm.equals(XMLCipher.RSA_OAEP))) {
+ return decodeWithAsymmetricKey(exchange, encodedDocument);
+ } else {
+ return decodeWithSymmetricKey(exchange, encodedDocument);
+ }
+ }
+
+ private Object decodeWithSymmetricKey(Exchange exchange, Document encodedDocument) throws Exception {
+ Key keyEncryptionKey;
if (xmlCipherAlgorithm.equals(XMLCipher.TRIPLEDES)) {
- keyEncryptionkey = generateEncryptionKey("DESede");
+ keyEncryptionKey = generateKeyEncryptionKey("DESede");
} else {
- keyEncryptionkey = generateEncryptionKey("AES");
+ keyEncryptionKey = generateKeyEncryptionKey("AES");
}
+ return decode(exchange, encodedDocument, keyEncryptionKey);
+ }
+
+ private Object decodeWithAsymmetricKey(Exchange exchange, Document encodedDocument) throws Exception {
+ if (this.keyStore == null) {
+ throw new IllegalStateException("A key store must be defined for asymmetric key decryption.");
+ }
+
+ Key keyEncryptionKey = getPrivateKey(this.keyStore, this.keyStoreAlias, this.keyStorePassword);
+ return decode(exchange, encodedDocument, keyEncryptionKey);
+ }
+
+ private Object decode(Exchange exchange, Document encodedDocument, Key keyEncryptionKey) throws Exception {
XMLCipher xmlCipher = XMLCipher.getInstance();
xmlCipher.init(XMLCipher.DECRYPT_MODE, null);
- xmlCipher.setKEK(keyEncryptionkey);
-
- Document encodedDocument = exchange.getContext().getTypeConverter().convertTo(Document.class, exchange, is);
+ xmlCipher.setKEK(keyEncryptionKey);
if (secureTag.equalsIgnoreCase("")) {
encodedDocument = xmlCipher.doFinal(encodedDocument, encodedDocument.getDocumentElement());
} else {
NodeIterator iter =
- XPathAPI.selectNodeIterator(encodedDocument, secureTag);
+ XPathAPI.selectNodeIterator(encodedDocument, secureTag);
Node node;
while ((node = iter.nextNode()) != null) {
- Document temp = xmlCipher.doFinal(encodedDocument, (Element) node, getSecureTagContents());
- encodedDocument.importNode(temp.getDocumentElement().cloneNode(true), true);
+ if (getSecureTagContents()) {
+ Document temp = xmlCipher.doFinal(encodedDocument, (Element) node, true);
+ encodedDocument.importNode(temp.getDocumentElement().cloneNode(true), true);
+ } else {
+ NodeList childNodes = node.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ if (childNode.getLocalName().equals("EncryptedData")) {
+ Document temp = xmlCipher.doFinal(encodedDocument, (Element) childNode, false);
+ encodedDocument.importNode(temp.getDocumentElement().cloneNode(true), true);
+ }
+ }
+ }
}
}
-
+
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
DOMSource source = new DOMSource(encodedDocument);
@@ -167,8 +386,11 @@ public class XMLSecurityDataFormat imple
// Return the decrypted data
return bos.toByteArray();
}
+
+
+ private Key generateKeyEncryptionKey(String algorithm) throws
+ InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
- private Key generateEncryptionKey(String algorithm) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
DESedeKeySpec keySpec;
Key secretKey;
try {
@@ -188,11 +410,30 @@ public class XMLSecurityDataFormat imple
}
return secretKey;
}
+
+ private Key generateDataEncryptionKey() throws Exception {
+ KeyGenerator keyGenerator = null;
+ if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.TRIPLEDES)) {
+ keyGenerator = KeyGenerator.getInstance("DESede");
+ } else {
+ keyGenerator = KeyGenerator.getInstance("AES");
+ }
+ if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128)) {
+ keyGenerator.init(128);
+ } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192)) {
+ keyGenerator.init(192);
+ } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256)) {
+ keyGenerator.init(256);
+ }
+ return keyGenerator.generateKey();
+ }
+
+ private void embedKeyInfoInEncryptedData(Document document, XMLCipher keyCipher, XMLCipher xmlCipher, Key dataEncryptionkey)
+ throws XMLEncryptionException {
- private void embedKeyInfoInEncryptedData(Document document, XMLCipher keyCipher, XMLCipher xmlCipher, Key dataEncryptionkey) throws XMLEncryptionException {
EncryptedKey encryptedKey = keyCipher.encryptKey(document, dataEncryptionkey);
KeyInfo keyInfo = new KeyInfo(document);
- keyInfo.add(encryptedKey);
+ keyInfo.add(encryptedKey);
EncryptedData encryptedDataElement = xmlCipher.getEncryptedData();
encryptedDataElement.setKeyInfo(keyInfo);
}
@@ -211,6 +452,16 @@ public class XMLSecurityDataFormat imple
return algorithmKeyWrap;
}
+
+ private String getRecipientKeyAlias(Exchange exchange) {
+ String alias = exchange.getIn().getHeader(XML_ENC_RECIPIENT_ALIAS, String.class);
+ if (alias != null) {
+ exchange.getIn().setHeader(XML_ENC_RECIPIENT_ALIAS, null);
+ } else {
+ alias = recipientKeyAlias;
+ }
+ return alias;
+ }
public String getXmlCipherAlgorithm() {
return xmlCipherAlgorithm;
@@ -219,6 +470,22 @@ public class XMLSecurityDataFormat imple
public void setXmlCipherAlgorithm(String xmlCipherAlgorithm) {
this.xmlCipherAlgorithm = xmlCipherAlgorithm;
}
+
+ public String getKeyCyperAlgorithm() {
+ return keyCipherAlgorithm;
+ }
+
+ public void setKeyCipherAlgorithm(String keyCipherAlgorithm) {
+ this.keyCipherAlgorithm = keyCipherAlgorithm;
+ }
+
+ public String getRecipientKeyAlias() {
+ return this.recipientKeyAlias;
+ }
+
+ public void setRecipientKeyAlias(String recipientKeyAlias) {
+ this.recipientKeyAlias = recipientKeyAlias;
+ }
public byte[] getPassPhrase() {
return passPhrase;
@@ -247,5 +514,44 @@ public class XMLSecurityDataFormat imple
public void setSecureTagContents(boolean secureTagContents) {
this.secureTagContents = secureTagContents;
}
-
+
+ public KeyStore getKeyStore() {
+ return this.keyStore;
+ }
+
+ public void setKeyStore(KeyStore keyStore) {
+ this.keyStore = keyStore;
+ }
+
+ public KeyStore getTrustStore() {
+ return this.trustStore;
+ }
+
+ public void setTrustStore(KeyStore trustStore) {
+ this.trustStore = trustStore;
+ }
+
+ public String getKeyStoreAlias() {
+ return this.keyStoreAlias;
+ }
+
+ public void setKeyStoreAlias(String keyStoreAlias) {
+ this.keyStoreAlias = keyStoreAlias;
+ }
+
+ public String getKeyStorePassword() {
+ return this.keyStorePassword;
+ }
+
+ public void setKeyStorePassword(String keyStorePassword) {
+ this.keyStorePassword = keyStorePassword;
+ }
+
+ public String getTrustStorePassowrd() {
+ return this.trustStorePassword;
+ }
+
+ public void setTrustStorePassword(String trustStorePassword) {
+ this.trustStorePassword = trustStorePassword;
+ }
}
Modified: camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java?rev=1137849&r1=1137848&r2=1137849&view=diff
==============================================================================
--- camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java (original)
+++ camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java Tue Jun 21 02:42:46 2011
@@ -18,6 +18,11 @@ package org.apache.camel.dataformat.xmls
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.net.URL;
+import java.security.KeyStore;
+import java.util.Map;
+
+import javax.xml.transform.OutputKeys;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
@@ -26,36 +31,43 @@ import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
import org.apache.camel.converter.jaxp.XmlConverter;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.apache.xml.security.encryption.XMLCipher;
+import org.junit.Ignore;
import org.junit.Test;
-
/**
* Unit test of the encryptXML data format.
*/
public class XMLSecurityDataFormatTest extends CamelTestSupport {
- private static final String XML_FRAGMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"
- + "<cheesesites>"
- + "<netherlands>"
- + "<source>cow</source>"
- + "<cheese>gouda</cheese>"
- + "</netherlands>"
- + "<italy>"
- + "<source>cow</source>"
- + "<cheese>gorgonzola</cheese>"
- + "</italy>"
- + "<france>"
- + "<source>goat</source>"
- + "<cheese>brie</cheese>"
- + "</france>"
- + "</cheesesites>";
+ private static final String XML_FRAGMENT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ + "<cheesesites>"
+ + "<netherlands>"
+ + "<source>cow</source>"
+ + "<cheese>gouda</cheese>"
+ + "</netherlands>"
+ + "<italy>"
+ + "<source>cow</source>"
+ + "<cheese>gorgonzola</cheese>"
+ + "</italy>"
+ + "<france>"
+ + "<source>goat</source>"
+ + "<cheese>brie</cheese>"
+ + "</france>"
+ + "</cheesesites>";
@Override
public boolean isUseRouteBuilder() {
return false;
}
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ context.getProperties().put(XmlConverter.OUTPUT_PROPERTIES_PREFIX + OutputKeys.ENCODING, "UTF-8");
+ }
private void sendText() throws Exception {
template.send("direct:start", new Processor() {
@@ -66,61 +78,117 @@ public class XMLSecurityDataFormatTest e
in.setBody(XML_FRAGMENT);
log.info("xmlFragment: " + XML_FRAGMENT);
}
-
});
}
+
+ private void testEncryption() throws Exception {
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:encrypted", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(1);
+ context.start();
+ sendText();
+ resultEndpoint.assertIsSatisfied(100);
+ Exchange exchange = resultEndpoint.getExchanges().get(0);
+ Document inDoc = getDocumentForInMessage(exchange);
+ if (log.isDebugEnabled()) {
+ logMessage(exchange, inDoc);
+ }
+ assertTrue("The XML message has no encrypted data.", hasEncryptedData(inDoc));
+ }
+
+ private void testDecryption() throws Exception {
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:decrypted", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(1);
+ // verify that the message was encrypted before checking that it is decrypted
+ testEncryption();
+
+ resultEndpoint.assertIsSatisfied(100);
+ Exchange exchange = resultEndpoint.getExchanges().get(0);
+ Document inDoc = getDocumentForInMessage(exchange);
+ if (log.isDebugEnabled()) {
+ logMessage(exchange, inDoc);
+ }
+ assertFalse("The XML message has encrypted data.", hasEncryptedData(inDoc));
+
+ // verify that the decrypted message matches what was sent
+ XmlConverter converter = new XmlConverter();
+ String xmlStr = converter.toString(inDoc, exchange);
+ assertTrue(xmlStr.equals(XML_FRAGMENT));
+ }
+
+ private boolean hasEncryptedData(Document doc) throws Exception {
+ NodeList nodeList = doc.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#", "EncryptedData");
+ return nodeList.getLength() > 0;
+ }
+
+ private void logMessage(Exchange exchange, Document inDoc) throws Exception {
+ XmlConverter converter = new XmlConverter();
+ String xmlStr = converter.toString(inDoc, exchange);
+ log.debug(xmlStr);
+ }
+
+ private Document getDocumentForInMessage(Exchange exchange) {
+ byte[] body = exchange.getIn().getBody(byte[].class);
+ Document d = createDocumentfromInputStream(new ByteArrayInputStream(body));
+ return d;
+ }
+
+ private Document createDocumentfromInputStream(InputStream is) {
+ return context.getTypeConverter().convertTo(Document.class, is);
+ }
/*
* Encryption Tests
*/
+
@Test
public void testFullPayloadXMLEncryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML().process(new EncryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML()
+ .to("mock:encrypted");
}
});
- context.start();
-
- sendText();
+ testEncryption();
}
@Test
- public void testPartialPayloadXMLContentEncryption() throws Exception {
+ public void testPartialPayloadXMLContentEncryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/italy/cheese", true).process(new EncryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy/cheese", true)
+ .to("mock:encrypted");
}
});
- context.start();
-
- sendText();
+ testEncryption();
}
@Test
public void testPartialPayloadMultiNodeXMLContentEncryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/*/cheese", true).process(new EncryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/*/cheese", true)
+ .to("mock:encrypted");
}
});
- context.start();
-
- sendText();
+ testEncryption();
}
@Test
public void testPartialPayloadXMLElementEncryptionWithKey() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/france/cheese", false, "Just another 24 Byte key").process(new EncryptedXMLMessageProcessor());
- }
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/france/cheese", false, "Just another 24 Byte key")
+ .to("mock:encrypted");
+ }
});
- context.start();
-
- sendText();
+ testEncryption();
}
+ @Ignore
@Test
public void testPartialPayloadXMLElementEncryptionWithKeyAndAlgorithm() throws Exception {
final byte[] bits128 = {
@@ -132,14 +200,81 @@ public class XMLSecurityDataFormatTest e
final String passCode = new String(bits128);
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/netherlands", false, passCode, XMLCipher.AES_128).process(new EncryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/netherlands", false, passCode, XMLCipher.AES_128)
+ .to("mock:encrypted");
}
});
- context.start();
+ testEncryption();
+ }
- sendText();
+ @Ignore
+ @Test
+ public void testFullPayloadAsymmetricKeyEncryption() throws Exception {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ URL trustStoreUrl = getClass().getClassLoader().getResource("sender.ts");
+ trustStore.load(trustStoreUrl.openStream(), "password".toCharArray());
+
+ final XMLSecurityDataFormat xmlEncDataFormat = new XMLSecurityDataFormat();
+ xmlEncDataFormat.setKeyCipherAlgorithm(XMLCipher.RSA_v1dot5);
+ xmlEncDataFormat.setXmlCipherAlgorithm(XMLCipher.AES_256);
+ xmlEncDataFormat.setTrustStore(trustStore);
+ xmlEncDataFormat.setTrustStorePassword("password");
+ xmlEncDataFormat.setRecipientKeyAlias("recipient");
+
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal(xmlEncDataFormat).to("mock:encrypted");
+ }
+ });
+ testEncryption();
}
+ @Ignore
+ @Test
+ public void testPartialPayloadAsymmetricKeyEncryptionWithContextTruststoreProperties() throws Exception {
+ Map<String, String> contextProps = context.getProperties();
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_URL,
+ getClass().getClassLoader().getResource("sender.ts").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_PASSWORD, "password");
+
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy/cheese", true, "recipient", XMLCipher.AES_256, XMLCipher.RSA_v1dot5)
+ .to("mock:encrypted");
+ }
+ });
+ testEncryption();
+ }
+
+ @Ignore
+ @Test
+ public void testPartialPayloadAsymmetricKeyEncryptionWithExchangeRecipientAlias() throws Exception {
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:foo", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(1);
+
+ Map<String, String> contextProps = context.getProperties();
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_URL,
+ getClass().getClassLoader().getResource("sender.ts").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_PASSWORD, "password");
+
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .process(new Processor() {
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setHeader(XMLSecurityDataFormat.XML_ENC_RECIPIENT_ALIAS, "recipient");
+ }
+ })
+ .marshal().secureXML("//cheesesites/italy/cheese", true, null, XMLCipher.AES_256, XMLCipher.RSA_v1dot5)
+ .to("mock:encrypted");
+ }
+ });
+ testEncryption();
+ }
+
/*
* Decryption Tests
*/
@@ -147,53 +282,51 @@ public class XMLSecurityDataFormatTest e
public void testFullPayloadXMLDecryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML().unmarshal().secureXML().process(new DecryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML().to("mock:encrypted")
+ .unmarshal().secureXML().to("mock:decrypted");
}
});
- context.start();
-
- sendText();
+ testDecryption();
}
@Test
public void testPartialPayloadXMLContentDecryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/italy/cheese", true).
- unmarshal().secureXML("//cheesesites/italy/cheese", true).process(new DecryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy/cheese", true).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/italy/cheese", true).to("mock:decrypted");
}
});
- context.start();
-
- sendText();
+ testDecryption();
}
@Test
public void testPartialPayloadMultiNodeXMLContentDecryption() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/*/cheese", true).
- unmarshal().secureXML("//cheesesites/*/cheese", true).process(new DecryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/*/cheese", true).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/*/cheese", true).to("mock:decrypted");
}
});
- context.start();
-
- sendText();
+ testDecryption();
}
@Test
public void testPartialPayloadXMLElementDecryptionWithKey() throws Exception {
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("//cheesesites/france/cheese", false, "Just another 24 Byte key").
- unmarshal().secureXML("//cheesesites/france", false, "Just another 24 Byte key").process(new DecryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/france/cheese", false, "Just another 24 Byte key").to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/france", false, "Just another 24 Byte key").to("mock:decrypted");
}
});
- context.start();
-
- sendText();
+ testDecryption();
}
+ @Ignore
@Test
public void testPartialPayloadXMLContentDecryptionWithKeyAndAlgorithm() throws Exception {
final byte[] bits128 = {
@@ -204,58 +337,62 @@ public class XMLSecurityDataFormatTest e
final String passCode = new String(bits128);
context.addRoutes(new RouteBuilder() {
public void configure() {
- from("direct:start").marshal().secureXML("cheese", true, passCode, XMLCipher.AES_128).
- unmarshal().secureXML("cheese", true, passCode, XMLCipher.AES_128).process(new DecryptedXMLMessageProcessor());
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy", true, passCode, XMLCipher.AES_128).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/italy", true, passCode, XMLCipher.AES_128).to("mock:decrypted");
}
});
- context.start();
-
- sendText();
+ testDecryption();
}
+ @Ignore
+ @Test
+ public void testFullPayloadAsymmetricKeyDecryption() throws Exception {
- private class EncryptedXMLMessageProcessor implements Processor {
-
- public void process(Exchange exchange) throws Exception {
- byte[] body = exchange.getIn().getBody(byte[].class);
-
- Document d = createDocumentfromInputStream(new ByteArrayInputStream(body));
+ Map<String, String> contextProps = context.getProperties();
+ // context properties for encryption
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_URL, getClass().getClassLoader().getResource("sender.ts").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_PASSWORD, "password");
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_RECIPIENT_ALIAS, "recipient");
+
+ // context properties for decryption
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_URL, getClass().getClassLoader().getResource("recipient.ks").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_PASSWORD, "password");
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_ALIAS, "recipient");
- // write to a string
- XmlConverter converter = new XmlConverter();
- String xmlStr = converter.toString(d, exchange);
-
- NodeList nodeList = d.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#", "EncryptedData");
- if (nodeList.getLength() >= 0) {
- assertTrue(true);
- } else {
- assertTrue(false);
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("", true, null, XMLCipher.AES_256, XMLCipher.RSA_v1dot5).to("mock:encrypted")
+ .unmarshal().secureXML("", true, null, XMLCipher.AES_256, XMLCipher.RSA_v1dot5).to("mock:decrypted");
}
- }
+ });
+ testDecryption();
}
- private class DecryptedXMLMessageProcessor implements Processor {
+ @Ignore
+ @Test
+ public void testPartialPayloadAsymmetricKeyDecryption() throws Exception {
- public void process(Exchange exchange) throws Exception {
- byte[] body = exchange.getIn().getBody(byte[].class);
+ Map<String, String> contextProps = context.getProperties();
- Document d = createDocumentfromInputStream(new ByteArrayInputStream(body));
+ // context properties for encryption
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_URL, getClass().getClassLoader().getResource("sender.ts").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_TRUST_STORE_PASSWORD, "password");
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_RECIPIENT_ALIAS, "recipient");
+
+ // context properties for decryption
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_URL, getClass().getClassLoader().getResource("recipient.ks").toString());
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_PASSWORD, "password");
+ contextProps.put(XMLSecurityDataFormat.XML_ENC_KEY_STORE_ALIAS, "recipient");
- // write to a string
- XmlConverter converter = new XmlConverter();
- String xmlStr = converter.toString(d, exchange);
-
- NodeList nodeList = d.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#", "EncryptedData");
- if (nodeList.getLength() == 0) {
- assertTrue(true);
- } else {
- assertTrue(false);
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy", true, null, XMLCipher.AES_256, XMLCipher.RSA_v1dot5).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/italy", true, null, XMLCipher.AES_256, XMLCipher.RSA_v1dot5).to("mock:decrypted");
}
- }
- }
-
-
- private Document createDocumentfromInputStream(InputStream is) {
- return context.getTypeConverter().convertTo(Document.class, is);
+ });
+ testDecryption();
}
}
Modified: camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/log4j.properties?rev=1137849&r1=1137848&r2=1137849&view=diff
==============================================================================
--- camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/log4j.properties (original)
+++ camel/branches/camel-2.7.x/components/camel-xmlsecurity/src/test/resources/log4j.properties Tue Jun 21 02:42:46 2011
@@ -20,10 +20,12 @@
#
log4j.rootLogger=INFO, file
+#log4j.logger.org.apache.camel.dataformat.xmlsecurity=DEBUG
+
# CONSOLE appender not used by default
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=%d %-5p %c{1} - %m %n
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=%d %-5p %c{1} - %m %n
# File appender
log4j.appender.file=org.apache.log4j.FileAppender