You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ni...@apache.org on 2014/09/16 14:21:54 UTC

git commit: CAMEL-7802 XML Signature: parameter for output character encoding and parent node via XPath with thanks to Franz

Repository: camel
Updated Branches:
  refs/heads/master 0d94bfe0c -> b8ca2bac1


CAMEL-7802 XML Signature: parameter for output character encoding and parent node via XPath with thanks to Franz


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/b8ca2bac
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/b8ca2bac
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/b8ca2bac

Branch: refs/heads/master
Commit: b8ca2bac1d4003140db0283ee4da7788572e844f
Parents: 0d94bfe
Author: Willem Jiang <wi...@gmail.com>
Authored: Tue Sep 16 20:20:58 2014 +0800
Committer: Willem Jiang <wi...@gmail.com>
Committed: Tue Sep 16 20:21:33 2014 +0800

----------------------------------------------------------------------
 .../xmlsecurity/XmlSignatureEndpoint.java       |  10 +
 .../xmlsecurity/XmlSignerEndpoint.java          |   8 +
 .../api/DefaultXmlSignature2Message.java        |  14 +-
 .../xmlsecurity/api/XmlSignature2Message.java   |  10 +-
 .../xmlsecurity/api/XmlSignatureHelper.java     | 109 ++++++--
 .../processor/XmlSignatureConfiguration.java    |  17 ++
 .../processor/XmlSignerConfiguration.java       |  42 ++-
 .../processor/XmlSignerProcessor.java           |  75 ++++--
 .../processor/XmlVerifierProcessor.java         |   6 +
 .../xmlsecurity/ECDSASignatureTest.java         |   2 +-
 .../xmlsecurity/SpringXmlSignatureTest.java     |  27 ++
 .../component/xmlsecurity/XmlSignatureTest.java | 253 +++++++++++++++++--
 .../xmlsecurity/SpringXmlSignatureTests.xml     |  16 ++
 13 files changed, 510 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignatureEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignatureEndpoint.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignatureEndpoint.java
index 9bec535..3633f04 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignatureEndpoint.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignatureEndpoint.java
@@ -101,5 +101,15 @@ public abstract class XmlSignatureEndpoint extends DefaultEndpoint {
 
     public void setSchemaResourceUri(String schemaResourceUri) {
         getConfiguration().setSchemaResourceUri(schemaResourceUri);
+        
     }
+    
+    public String getOutputXmlEncoding() {
+        return getConfiguration().getOutputXmlEncoding();
+    }
+    
+    public void setOutputXmlEncoding(String encoding) {
+        getConfiguration().setOutputXmlEncoding(encoding);
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignerEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignerEndpoint.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignerEndpoint.java
index 26fd77a..6b67e92 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignerEndpoint.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/XmlSignerEndpoint.java
@@ -184,5 +184,13 @@ public class XmlSignerEndpoint extends XmlSignatureEndpoint {
     public void setSignatureId(String signatureId) {
         getConfiguration().setSignatureId(signatureId);
     }
+    
+    public XPathFilterParameterSpec getParentXpath() {
+        return getConfiguration().getParentXpath();
+    }
+    
+    public void setParentXpath(XPathFilterParameterSpec parentXpath) {
+        getConfiguration().setParentXpath(parentXpath);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXmlSignature2Message.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXmlSignature2Message.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXmlSignature2Message.java
index e11c89f..0e3a437 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXmlSignature2Message.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/DefaultXmlSignature2Message.java
@@ -17,7 +17,6 @@
 package org.apache.camel.component.xmlsecurity.api;
 
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -29,9 +28,6 @@ import javax.xml.crypto.dsig.XMLObject;
 import javax.xml.crypto.dsig.XMLSignature;
 import javax.xml.crypto.dsig.XMLSignatureException;
 import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactoryConfigurationError;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpression;
 
@@ -40,10 +36,12 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import org.apache.camel.Exchange;
 import org.apache.camel.Message;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+
 /**
  * Maps the XML signature to a camel message. A output node is determined from
  * the XML signature document via a node search and then serialized and set to
@@ -194,13 +192,17 @@ public class DefaultXmlSignature2Message implements XmlSignature2Message {
     }
 
     protected void transformNodeToByteArrayAndSetToOutputMessage(Input input, Message output, Node node)
-        throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException, IOException {
+        throws Exception {
 
         ByteArrayOutputStream os = new ByteArrayOutputStream();
-        XmlSignatureHelper.transformToOutputStream(node, os, omitXmlDeclaration(output, input));
+        XmlSignatureHelper.transformToOutputStream(node, os, omitXmlDeclaration(output, input), input.getOutputXmlEncoding());
         output.setBody(os.toByteArray());
+        if (input.getOutputXmlEncoding() != null) {
+            output.setHeader(Exchange.CHARSET_NAME, input.getOutputXmlEncoding());
+        }
     }
 
+
     protected Node getOutputNodeViaXPath(Input input) throws Exception { //NOPMD
         checkSearchValueNotNull(input);
         checkSearchValueOfType(XPathFilterParameterSpec.class, input);

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignature2Message.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignature2Message.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignature2Message.java
index 6048156..c5e8149 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignature2Message.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignature2Message.java
@@ -22,7 +22,6 @@ import javax.xml.crypto.dsig.Reference;
 import javax.xml.crypto.dsig.XMLObject;
 
 import org.w3c.dom.Document;
-
 import org.apache.camel.Message;
 
 /**
@@ -89,6 +88,15 @@ public interface XmlSignature2Message {
          * the document set to the output message.
          */
         Boolean getRemoveSignatureElements();
+
+        /**
+         * The character encoding of the resulting XML document. Can be
+         * <code>null</code>. If <code>null</code> then the encoding of the
+         * original XML document is used.
+         * 
+         */
+        String getOutputXmlEncoding();
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureHelper.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureHelper.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureHelper.java
index 2593e3b..6111457 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureHelper.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/api/XmlSignatureHelper.java
@@ -39,14 +39,6 @@ import javax.xml.namespace.NamespaceContext;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
 import javax.xml.validation.Schema;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathExpression;
@@ -56,6 +48,10 @@ import javax.xml.xpath.XPathFactory;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+import org.w3c.dom.ls.DOMImplementationLS;
+import org.w3c.dom.ls.LSOutput;
+import org.w3c.dom.ls.LSSerializer;
 import org.xml.sax.SAXException;
 
 import org.apache.camel.util.IOHelper;
@@ -66,7 +62,7 @@ import org.apache.camel.util.IOHelper;
  */
 public final class XmlSignatureHelper {
     private XmlSignatureHelper() {
-        //Helper class
+        // Helper class
     }
 
     /**
@@ -162,7 +158,7 @@ public final class XmlSignatureHelper {
                 namespaceMap);
         return params;
     }
-    
+
     public static XPathFilterParameterSpec getXpathFilter(String xpath) {
         return getXpathFilter(xpath, null);
     }
@@ -332,7 +328,7 @@ public final class XmlSignatureHelper {
      * @throws Exception
      *             if an error during the reading of the XSL file occurs
      */
-    public static AlgorithmMethod getXslTransform(String path) throws Exception {
+    public static AlgorithmMethod getXslTransform(String path) throws Exception { //NOPMD
         InputStream is = readXslTransform(path);
         if (is == null) {
             throw new IllegalStateException(String.format("XSL file %s not found", path));
@@ -368,7 +364,7 @@ public final class XmlSignatureHelper {
         return transformXslt;
     }
 
-    protected static InputStream readXslTransform(String path) throws Exception {
+    protected static InputStream readXslTransform(String path) throws Exception { //NOPMD
         if (path == null) {
             throw new IllegalArgumentException("path is null");
         }
@@ -402,8 +398,7 @@ public final class XmlSignatureHelper {
         return newDocumentBuilder(disallowDoctypeDecl, null);
     }
 
-    public static DocumentBuilder newDocumentBuilder(Boolean disallowDoctypeDecl, Schema schema)
-        throws ParserConfigurationException {
+    public static DocumentBuilder newDocumentBuilder(Boolean disallowDoctypeDecl, Schema schema) throws ParserConfigurationException {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         dbf.setNamespaceAware(true);
         dbf.setValidating(false);
@@ -421,8 +416,22 @@ public final class XmlSignatureHelper {
         return dbf.newDocumentBuilder();
     }
 
-    public static void transformToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration)
-        throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException, IOException {
+    public static void transformToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration, String encoding) throws Exception { //NOPMD
+
+        if (node.getNodeType() == Node.TEXT_NODE) {
+            byte[] bytes = tranformTextNodeToByteArray(node, encoding);
+            os.write(bytes);
+        } else {
+            transformNonTextNodeToOutputStream(node, os, omitXmlDeclaration, encoding);
+        }
+    }
+
+    /**
+     * Use {@link #transformToOutputStream(Node, OutputStream, boolean, String)}
+     * instead.
+     */
+    @Deprecated
+    public static void transformToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration) throws Exception { //NOPMD
 
         if (node.getNodeType() == Node.TEXT_NODE) {
             byte[] bytes = tranformTextNodeToByteArray(node);
@@ -432,24 +441,74 @@ public final class XmlSignatureHelper {
         }
     }
 
-    public static void transformNonTextNodeToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration)
-        throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException {
+    /**
+     * Use
+     * {@link #transformNonTextNodeToOutputStream(Node, OutputStream, boolean, String)}
+     * instead.
+     */
+    @Deprecated
+    public static void transformNonTextNodeToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration) throws Exception { //NOPMD
+        transformNonTextNodeToOutputStream(node, os, omitXmlDeclaration, null);
+    }
 
-        TransformerFactory tf = TransformerFactory.newInstance();
-        Transformer trans = tf.newTransformer();
-        if (omitXmlDeclaration) {
-            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+    /**
+     * Serializes a node using a certain character encoding.
+     * 
+     * @param node
+     *            DOM node to serialize
+     * @param os
+     *            output stream, to which the node is serialized
+     * @param omitXmlDeclaration
+     *            indicator whether to omit the XML declaration or not
+     * @param encoding
+     *            character encoding, can be <code>null</code>, if
+     *            <code>null</code> then "UTF-8" is used
+     * @throws Exception
+     */
+    public static void transformNonTextNodeToOutputStream(Node node, OutputStream os, boolean omitXmlDeclaration, String encoding)
+        throws Exception { //NOPMD
+        // previously we used javax.xml.transform.Transformer, however the JDK xalan implementation did not work correctly with a specified encoding
+        // therefore we switched to DOMImplementationLS
+        if (encoding == null) {
+            encoding = "UTF-8";
         }
-        trans.transform(new DOMSource(node), new StreamResult(os));
+        DOMImplementationRegistry domImplementationRegistry = DOMImplementationRegistry.newInstance();
+        DOMImplementationLS domImplementationLS = (DOMImplementationLS) domImplementationRegistry.getDOMImplementation("LS");
+        LSOutput lsOutput = domImplementationLS.createLSOutput();
+        lsOutput.setEncoding(encoding);
+        lsOutput.setByteStream(os);
+        LSSerializer lss = domImplementationLS.createLSSerializer();
+        lss.getDomConfig().setParameter("xml-declaration", !omitXmlDeclaration);
+        lss.write(node, lsOutput);
     }
 
+    /** use {@link #tranformTextNodeToByteArray(Node, String)} instead. */
+    @Deprecated
     public static byte[] tranformTextNodeToByteArray(Node node) {
+        return tranformTextNodeToByteArray(node, null);
+    }
+
+    /**
+     * Trannsforms a text node to byte array using a certain character encoding.
+     * 
+     * @param node
+     *            text node
+     * @param encoding
+     *            character encoding, can be <code>null</code>, if
+     *            <code>null</code> then UTF-8 is used
+     * @return byte array, <code>null</code> if the node has not text content
+     * @throws IllegalStateException
+     *             if the encoding is not supported
+     */
+    public static byte[] tranformTextNodeToByteArray(Node node, String encoding) {
+        if (encoding == null) {
+            encoding = "UTF-8";
+        }
         String text = node.getTextContent();
         if (text != null) {
             try {
-                return text.getBytes("UTF-8");
+                return text.getBytes(encoding);
             } catch (UnsupportedEncodingException e) {
-                // should not happen
                 throw new IllegalStateException(e);
             }
         } else {

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignatureConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignatureConfiguration.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignatureConfiguration.java
index bc67c5a..b752e0a 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignatureConfiguration.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignatureConfiguration.java
@@ -44,6 +44,8 @@ public abstract class XmlSignatureConfiguration implements Cloneable, CamelConte
     private Boolean clearHeaders = Boolean.TRUE;
 
     private String schemaResourceUri;
+    
+    private String outputXmlEncoding;
 
     public XmlSignatureConfiguration() {
     }
@@ -177,5 +179,20 @@ public abstract class XmlSignatureConfiguration implements Cloneable, CamelConte
     public void setSchemaResourceUri(String schemaResourceUri) {
         this.schemaResourceUri = schemaResourceUri;
     }
+    
+    public String getOutputXmlEncoding() {
+        return outputXmlEncoding;
+    }
+
+    /**
+     * The character encoding of the resulting signed XML document. If
+     * <code>null</code> then the encoding of the original XML document is used.
+     * 
+     * @param outputXmlEncoding
+     *            character encoding
+     */
+    public void setOutputXmlEncoding(String outputXmlEncoding) {
+        this.outputXmlEncoding = outputXmlEncoding;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerConfiguration.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerConfiguration.java
index e2a25e6..37acb5f 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerConfiguration.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerConfiguration.java
@@ -108,6 +108,8 @@ public class XmlSignerConfiguration extends XmlSignatureConfiguration {
     private XmlSignatureProperties properties;
 
     private List<XPathFilterParameterSpec> xpathsToIdAttributes = Collections.emptyList();
+    
+    private XPathFilterParameterSpec parentXpath;
 
     /* references that should be resolved when the context changes */
     private String keyAccessorName;
@@ -279,13 +281,19 @@ public class XmlSignerConfiguration extends XmlSignatureConfiguration {
 
     /**
      * Local name of the parent element to which the XML signature element will
-     * be added. Only relevant for enveloped XML signature. Default value is
+     * be added. Only relevant for enveloped XML signature. Alternatively you can 
+     * also use {@link #setParentXpath(XPathFilterParameterSpec)}.
+     * 
+     * <p> Default value is
      * <code>null</code>. The value must be <code>null</code> for enveloping and
      * detached XML signature.
      * <p>
-     * This parameter for enveloped signature and the parameter
-     * {@link #setXpathsToIdAttributes(List)} for detached signature must not be
-     * set in the same configuration.
+     * This parameter or the parameter {@link #setParentXpath(XPathFilterParameterSpec)}
+     * for enveloped signature and the parameter {@link #setXpathsToIdAttributes(List)} 
+     * for detached signature must not be set in the same configuration.
+     * <p>
+     * If the parameters <tt>parentXpath</tt> and <tt>parentLocalName</tt> are specified
+     * in the same configuration then an exception is thrown.
      * 
      * @param parentLocalName
      *            local name
@@ -455,9 +463,9 @@ public class XmlSignerConfiguration extends XmlSignatureConfiguration {
      * You can also set the XPATH list dynamically via the header
      * {@link XmlSignatureConstants#HEADER_XPATHS_TO_ID_ATTRIBUTES}.
      * <p>
-     * The parameter {@link #setParentLocalName(String)} for enveloped signature
-     * and this parameter for detached signature must not be set in the same
-     * configuration.
+     * The parameter {@link #setParentLocalName(String)} or {@link #setParentXpath(XPathFilterParameterSpec)}
+     * for enveloped signature and this parameter for detached signature must not
+     * be set in the same configuration.
      * 
      * @param xpathsToIdAttributes
      */
@@ -469,4 +477,24 @@ public class XmlSignerConfiguration extends XmlSignatureConfiguration {
         }
     }
 
+    public XPathFilterParameterSpec getParentXpath() {
+        return parentXpath;
+    }
+
+    /** Sets the XPath to find the parent node in the enveloped case. 
+     * Either you specify the parent node via this method or the local name and namespace of the parent 
+     * with the methods {@link #setParentLocalName(String)} and {@link #setParentNamespace(String)}. 
+     * <p>
+     * Default value is <code>null</code>. The value must be <code>null</code> for enveloping and
+     * detached XML signature.
+     * <p>
+     * If the parameters <tt>parentXpath</tt> and <tt>parentLocalName</tt> are specified
+     * in the same configuration then an exception is thrown.
+     * 
+     * @param parentXpath xpath to the parent node, if the xpath returns several values then the first Element node is used
+     */
+    public void setParentXpath(XPathFilterParameterSpec parentXpath) {
+        this.parentXpath = parentXpath;
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
index 4607aff..6d774e2 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlSignerProcessor.java
@@ -217,9 +217,10 @@ public class XmlSignerProcessor extends XmlSignatureProcessor {
             Document outputDoc = sign(out);
 
             ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-            XmlSignatureHelper.transformNonTextNodeToOutputStream(outputDoc, outStream, omitXmlDeclaration(out));
+            XmlSignatureHelper.transformNonTextNodeToOutputStream(outputDoc, outStream, omitXmlDeclaration(out), getConfiguration().getOutputXmlEncoding());
             byte[] data = outStream.toByteArray();
             out.setBody(data);
+            setOutputEncodingToMessageHeader(out);
             clearMessageHeaders(out);
             LOG.debug("XML signature generation finished");
         } catch (Exception e) {
@@ -270,7 +271,7 @@ public class XmlSignerProcessor extends XmlSignatureProcessor {
                     signatureId = null;
                 }
 
-                // parent only relevant for enveloping or detached signature
+                // parent only relevant for enveloped or detached signature
                 Node parent = getParentOfSignature(out, node, contentReferenceUri, signatureType);
 
                 XmlSignatureProperties.Input input = new InputBuilder().contentDigestAlgorithm(getDigestAlgorithmUri()).keyInfo(keyInfo)
@@ -314,16 +315,31 @@ public class XmlSignerProcessor extends XmlSignatureProcessor {
     }
 
     private SignatureType determineSignatureType(Message message) throws XmlSignatureException {
+        if (getConfiguration().getParentLocalName() != null && getConfiguration().getParentXpath() != null) {
+            throw new XmlSignatureException(
+                    "The configuration of the XML signer component is wrong. The parent local name "
+                            + getConfiguration().getParentLocalName()
+                            + " and the parent XPath " + getConfiguration().getParentXpath().getXPath() + " are specified. You must not specify both parameters.");
+
+        }
 
-        boolean isEnveloped = getConfiguration().getParentLocalName() != null;
+        boolean isEnveloped = getConfiguration().getParentLocalName() != null || getConfiguration().getParentXpath() != null;
 
         boolean isDetached = getXpathToIdAttributes(message).size() > 0;
 
         if (isEnveloped && isDetached) {
-            throw new XmlSignatureException(
+            if (getConfiguration().getParentLocalName() != null) {
+                throw new XmlSignatureException(
                     "The configuration of the XML signer component is wrong. The parent local name "
                             + getConfiguration().getParentLocalName()
                             + " for an enveloped signature and the XPATHs to ID attributes for a detached signature are specified. You must not specify both parameters.");
+            } else {
+                throw new XmlSignatureException(
+                        "The configuration of the XML signer component is wrong. The parent XPath "
+                                + getConfiguration().getParentXpath().getXPath()
+                                + " for an enveloped signature and the XPATHs to ID attributes for a detached signature are specified. You must not specify both parameters.");
+
+            }
         }
 
         SignatureType result;
@@ -458,19 +474,41 @@ public class XmlSignerProcessor extends XmlSignatureProcessor {
         }
 
     }
-
+    
     protected Element getParentForEnvelopedCase(Document doc, Message inMessage) throws Exception { //NOPMD
-
-        NodeList parents = doc.getElementsByTagNameNS(getConfiguration().getParentNamespace(), getConfiguration().getParentLocalName());
-
-        if (parents == null || parents.getLength() == 0) {
-            throw new XmlSignatureFormatException(
-                    String.format(
-                            "Incoming message has wrong format: The parent element with the local name %s and the namespace %s was not found in the message to build an enveloped XML signature.",
-                            getConfiguration().getParentLocalName(), getConfiguration().getParentNamespace()));
+        if (getConfiguration().getParentXpath() != null) {
+            XPathFilterParameterSpec xp = getConfiguration().getParentXpath();
+            XPathExpression exp;
+            try {
+                exp = XmlSignatureHelper.getXPathExpression(xp);
+            } catch (XPathExpressionException e) {
+                throw new XmlSignatureException("The parent XPath " + getConfiguration().getParentXpath().getXPath() + " is wrongly configured: The XPath " + xp.getXPath() + " is invalid.", e);
+            }
+            NodeList list = (NodeList) exp.evaluate(doc.getDocumentElement(), XPathConstants.NODESET);
+            if (list == null || list.getLength() == 0) {
+                throw new XmlSignatureException("The parent XPath " + xp.getXPath() + " returned no result. Check the configuration of the XML signer component.");
+            }
+            int length = list.getLength();
+            for (int i = 0; i < length; i++) {
+                Node node = list.item(i);
+                if (node.getNodeType() == Node.ELEMENT_NODE) {
+                    // return the first element
+                    return (Element)node;
+                }
+            }
+            throw new XmlSignatureException("The parent XPath " + xp.getXPath() + " returned no element. Check the configuration of the XML signer component.");
+        } else {
+            // parent local name is not null!
+            NodeList parents = doc.getElementsByTagNameNS(getConfiguration().getParentNamespace(), getConfiguration().getParentLocalName());
+            if (parents == null || parents.getLength() == 0) {
+                throw new XmlSignatureFormatException(
+                        String.format(
+                                "Incoming message has wrong format: The parent element with the local name %s and the namespace %s was not found in the message to build an enveloped XML signature.",
+                                getConfiguration().getParentLocalName(), getConfiguration().getParentNamespace()));
+            }
+            // return the first element
+            return (Element) parents.item(0);
         }
-        // return the first element
-        return (Element) parents.item(0);
     }
 
     private Element getParentForDetachedCase(Document doc, Message inMessage, String referenceUri) throws XmlSignatureException {
@@ -800,6 +838,13 @@ public class XmlSignerProcessor extends XmlSignatureProcessor {
         }
         return keyInfo.getId();
     }
+    
+    protected void setOutputEncodingToMessageHeader(Message message) {
+        if (getConfiguration().getOutputXmlEncoding() != null) {
+            message.setHeader(Exchange.CHARSET_NAME, getConfiguration().getOutputXmlEncoding());
+        }
+    }
+
 
     private static class InputBuilder {
 

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlVerifierProcessor.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlVerifierProcessor.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlVerifierProcessor.java
index 37e2cc7..b606ec1 100644
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlVerifierProcessor.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/component/xmlsecurity/processor/XmlVerifierProcessor.java
@@ -204,9 +204,15 @@ public class XmlVerifierProcessor extends XmlSignatureProcessor {
                 return getConfiguration().getOutputNodeSearchType();
             }
 
+            @Override
             public Boolean getRemoveSignatureElements() {
                 return getConfiguration().getRemoveSignatureElements();
             }
+            
+            @Override
+            public String getOutputXmlEncoding() {
+                return getConfiguration().getOutputXmlEncoding();
+            }
 
         };
         getConfiguration().getXmlSignature2Message().mapToMessage(refsAndObjects, out);

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/ECDSASignatureTest.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/ECDSASignatureTest.java b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/ECDSASignatureTest.java
index 80da3a2..7e35d99 100644
--- a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/ECDSASignatureTest.java
+++ b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/ECDSASignatureTest.java
@@ -46,7 +46,7 @@ import org.junit.Test;
  */
 public class ECDSASignatureTest extends CamelTestSupport {
     
-    private static String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+    private static String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
         + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";
     
     private boolean canTest = true;

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
index 3f7f089..f3f0957 100644
--- a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
+++ b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTest.java
@@ -69,4 +69,31 @@ public class SpringXmlSignatureTest extends XmlSignatureTest {
                         + "schemaResourceUri=org/apache/camel/component/xmlsecurity/Test.xsd&signatureId=&clearHeaders=false");
         return endpoint;
     }
+    
+    @Override
+    XmlSignerEndpoint getSignatureEncpointForSignException() {
+        XmlSignerEndpoint endpoint = (XmlSignerEndpoint)context().getEndpoint(//
+            "xmlsecurity:sign://signexceptioninvalidkey?keyAccessor=#accessorRsa");
+        return endpoint;
+    }
+    
+    @Override
+    String getVerifierEndpointURIEnveloped() {
+        return "xmlsecurity:verify://enveloped?keySelector=#selectorRsa";
+    }
+
+    @Override
+    String getSignerEndpointURIEnveloped() {
+        return "xmlsecurity:sign://enveloped?keyAccessor=#accessorRsa&parentLocalName=root&parentNamespace=http://test/test";
+    }
+    
+    @Override
+    String getVerifierEncpointURIEnveloping() {
+        return "xmlsecurity:verify://enveloping?keySelector=#selectorRsa";
+    }
+
+    @Override
+    String getSignerEndpointURIEnveloping() {
+        return "xmlsecurity:sign://enveloping?keyAccessor=#accessorRsa";
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/XmlSignatureTest.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/XmlSignatureTest.java b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/XmlSignatureTest.java
index 0965d3c..a363e6a 100644
--- a/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/XmlSignatureTest.java
+++ b/components/camel-xmlsecurity/src/test/java/org/apache/camel/component/xmlsecurity/XmlSignatureTest.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
 import java.security.Key;
 import java.security.KeyException;
 import java.security.KeyPair;
@@ -66,7 +67,6 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.xml.sax.SAXException;
-
 import org.apache.camel.CamelContext;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
@@ -101,10 +101,9 @@ import org.apache.camel.test.junit4.CamelTestSupport;
 import org.junit.Before;
 import org.junit.Test;
 
-
 public class XmlSignatureTest extends CamelTestSupport {
 
-    private static String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+    private static String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
             + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";
     private KeyPair keyPair;
 
@@ -133,6 +132,8 @@ public class XmlSignatureTest extends CamelTestSupport {
                 .singletonList(XmlSignatureHelper.getXpathFilter("/ns:root/a/@ID", namespaceMap));
         registry.bind("xpathsToIdAttributes", xpaths);
 
+        registry.bind("parentXpathBean", getParentXPathBean());
+
         return registry;
     }
 
@@ -142,8 +143,8 @@ public class XmlSignatureTest extends CamelTestSupport {
             public void configure() throws Exception {
                 // START SNIPPET: enveloping XML signature
                 onException(XmlSignatureException.class).handled(true).to("mock:exception");
-                from("direct:enveloping").to("xmlsecurity:sign://enveloping?keyAccessor=#accessor&schemaResourceUri=")
-                        .to("xmlsecurity:verify://enveloping?keySelector=#selector").to("mock:result");
+                from("direct:enveloping").to(getSignerEndpointURIEnveloping()).to("mock:signed").to(getVerifierEncpointURIEnveloping())
+                        .to("mock:result");
                 // END SNIPPET: enveloping XML signature
             }
         }, new RouteBuilder() {
@@ -160,9 +161,8 @@ public class XmlSignatureTest extends CamelTestSupport {
             public void configure() throws Exception {
                 // START SNIPPET: enveloped XML signature
                 onException(XmlSignatureException.class).handled(true).to("mock:exception");
-                from("direct:enveloped")
-                        .to("xmlsecurity:sign://enveloped?keyAccessor=#accessor&parentLocalName=root&parentNamespace=http://test/test")
-                        .to("xmlsecurity:verify://enveloped?keySelector=#selector").to("mock:result");
+                from("direct:enveloped").to(getSignerEndpointURIEnveloped()).to("mock:signed").to(getVerifierEndpointURIEnveloped())
+                        .to("mock:result");
                 // END SNIPPET: enveloped XML signature
             }
         }, new RouteBuilder() {
@@ -208,12 +208,14 @@ public class XmlSignatureTest extends CamelTestSupport {
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
-                // START SNIPPET: transforms XSLT,XPath - secure Validation disabled
+                // START SNIPPET: transforms XSLT,XPath - secure Validation
+                // disabled
                 from("direct:transformsXsltXPathSecureValDisabled")
                         .to("xmlsecurity:sign://transformsXsltXPathSecureValDisabled?keyAccessor=#accessor&transformMethods=#transformsXsltXPath",
                                 "xmlsecurity:verify://transformsXsltXPathSecureValDisabled?keySelector=#selector&secureValidation=false")
                         .to("mock:result");
-                // END SNIPPET: transforms XSLT,XPath - secure Validation disabled
+                // END SNIPPET: transforms XSLT,XPath - secure Validation
+                // disabled
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
@@ -314,38 +316,34 @@ public class XmlSignatureTest extends CamelTestSupport {
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
-                // START SNIPPET: NoSuchAlgorithmException
                 onException(XmlSignatureException.class).handled(true).to("mock:exception");
                 from("direct:noSuchAlgorithmException")
                         .to("xmlsecurity:sign://noSuchAlgorithmException?keyAccessor=#accessor&signatureAlgorithm=wrongalgorithm&digestAlgorithm=http://www.w3.org/2001/04/xmlenc#sha512")
                         .to("mock:result");
-                // END SNIPPET: NoSuchAlgorithmException
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
-                // START SNIPPET: verifier exceptions
                 onException(XmlSignatureException.class).handled(false).to("mock:exception");
                 from("direct:verifyexceptions").to("xmlsecurity:verify://verifyexceptions?keySelector=#selector").to("mock:result");
-                // END SNIPPET: verifier exceptions
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
-                // START SNIPPET: verifier InvalidKeyException
                 onException(XmlSignatureException.class).handled(false).to("mock:exception");
                 from("direct:verifyInvalidKeyException").to("xmlsecurity:verify://verifyInvalidKeyException?keySelector=#selector").to(
                         "mock:result");
-                // END SNIPPET: verifier exceptions
             }
         }, new RouteBuilder() {
             public void configure() throws Exception {
-                // START SNIPPET: verifier InvalidHashException
                 onException(XmlSignatureException.class).handled(false).to("mock:exception");
                 from("direct:invalidhash").to(
                         "xmlsecurity:verify://invalidhash?keySelector=#selectorKeyValue&baseUri=#baseUri&secureValidation=false").to(
                         "mock:result");
-                // END SNIPPET: verifier InvalidHashException
             }
-        }, new RouteBuilder() {
+        }, createDetachedRoute(), createRouteForEnvelopedWithParentXpath() };
+    }
+
+    RouteBuilder createDetachedRoute() {
+        return new RouteBuilder() {
             public void configure() throws Exception {
                 // START SNIPPET: detached XML signature
                 onException(Exception.class).handled(false).to("mock:exception");
@@ -357,8 +355,18 @@ public class XmlSignatureTest extends CamelTestSupport {
                         .to("mock:verified");
                 // END SNIPPET: detached XML signature
             }
-        }
+        };
+    }
 
+    private RouteBuilder createRouteForEnvelopedWithParentXpath() {
+        return new RouteBuilder() {
+            public void configure() throws Exception {
+                // START SNIPPET: enveloped XML signature with parent XPath
+                onException(XmlSignatureException.class).handled(false).to("mock:exception");
+                from("direct:envelopedParentXpath").to("xmlsecurity:sign://enveloped?keyAccessor=#accessor&parentXpath=#parentXpathBean")
+                        .to("mock:signed").to(getVerifierEndpointURIEnveloped()).to("mock:result");
+                // END SNIPPET: enveloped XML signature with parent XPath
+            }
         };
     }
 
@@ -474,7 +482,7 @@ public class XmlSignatureTest extends CamelTestSupport {
     @Test
     public void testSetTransformMethodXpath2InRouteDefinition() throws Exception {
         // example from http://www.w3.org/TR/2002/REC-xmldsig-filter2-20021108/
-        String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+        String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
                 + "<Document xmlns=\"http://test/test\">                             "
                 + "<ToBeSigned>                                                     "
                 + "   <!-- comment -->                                              "
@@ -791,7 +799,8 @@ public class XmlSignatureTest extends CamelTestSupport {
 
     @Test
     public void testSignatureIdAtributeNull() throws Exception {
-        // the signature Id parameter must be empty, this is set in the URI already
+        // the signature Id parameter must be empty, this is set in the URI
+        // already
         Element sigEle = testDetachedSignatureInternal();
         Attr attr = sigEle.getAttributeNode("Id");
         assertNull("Signature element contains Id attribute", attr);
@@ -821,7 +830,7 @@ public class XmlSignatureTest extends CamelTestSupport {
 
     private Element testDetachedSignatureInternal() throws InterruptedException, XPathExpressionException, SAXException, IOException,
             ParserConfigurationException {
-        String detachedPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + //
+        String detachedPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
                 "<ns:root xmlns:ns=\"http://test\"><a ID=\"myID\"><b>bValue</b></a></ns:root>";
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMessageCount(1);
@@ -860,7 +869,7 @@ public class XmlSignatureTest extends CamelTestSupport {
 
     void testDetached2Xpaths(String xpath1exp, String xpath2exp) throws InterruptedException, XPathExpressionException, SAXException,
             IOException, ParserConfigurationException {
-        String detachedPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + //
+        String detachedPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
                 "<ns:root xmlns:ns=\"http://test\"><test ID=\"myID\"><b>bValue</b><ts:B xmlns:ts=\"http://testB\"><C ID=\"cID\"><D>dvalue</D></C></ts:B></test></ns:root>";
         MockEndpoint mock = getMockEndpoint("mock:result");
         mock.expectedMessageCount(1);
@@ -1007,6 +1016,164 @@ public class XmlSignatureTest extends CamelTestSupport {
                         + " has no parent element. The element must have a parent element in the configured detached case.", null);
     }
 
+    @Test
+    public void testOutputXmlEncodingEnveloping() throws Exception {
+
+        String inputEncoding = "UTF-8";
+        String signerEncoding = "UTF-16LE";
+        String outputEncoding = "ISO-8859-1"; // latin 1
+
+        String signerEndpointUri = getSignerEndpointURIEnveloping();
+        String verifierEndpointUri = getVerifierEncpointURIEnveloping();
+
+        String directStart = "direct:enveloping";
+
+        checkOutputEncoding(inputEncoding, signerEncoding, outputEncoding, signerEndpointUri, verifierEndpointUri, directStart);
+    }
+
+    String getVerifierEncpointURIEnveloping() {
+        return "xmlsecurity:verify://enveloping?keySelector=#selector";
+    }
+
+    String getSignerEndpointURIEnveloping() {
+        return "xmlsecurity:sign://enveloping?keyAccessor=#accessor&schemaResourceUri=";
+    }
+
+    @Test
+    public void testOutputXmlEncodingEnveloped() throws Exception {
+
+        String inputEncoding = "UTF-8";
+        String signerEncoding = "UTF-16LE";
+        String outputEncoding = "ISO-8859-1"; // latin 1
+
+        String signerEndpointUri = getSignerEndpointURIEnveloped();
+        String verifierEndpointUri = getVerifierEndpointURIEnveloped();
+
+        String directStart = "direct:enveloped";
+
+        checkOutputEncoding(inputEncoding, signerEncoding, outputEncoding, signerEndpointUri, verifierEndpointUri, directStart);
+    }
+
+    String getVerifierEndpointURIEnveloped() {
+        return "xmlsecurity:verify://enveloped?keySelector=#selector";
+    }
+
+    String getSignerEndpointURIEnveloped() {
+        return "xmlsecurity:sign://enveloped?keyAccessor=#accessor&parentLocalName=root&parentNamespace=http://test/test";
+    }
+
+    private byte[] getPayloadForEncoding(String encoding) {
+        String s = "<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n"
+                + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";
+        return s.getBytes(Charset.forName(encoding));
+    }
+
+    @Test
+    public void testExceptionParentLocalNameAndXPathSet() throws Exception {
+
+        XmlSignerEndpoint endpoint = getSignatureEncpointForSignException();
+        MockEndpoint mock = setupExceptionMock();
+        try {
+            endpoint.setParentXpath(getNodeSerachXPath());
+            endpoint.setParentLocalName("root");
+            sendBody("direct:signexceptions", payload);
+            assertMockEndpointsSatisfied();
+            checkThrownException(mock, XmlSignatureException.class, "The configuration of the XML signer component is wrong. " + //
+                    "The parent local name root and the parent XPath //pre:root are specified. You must not specify both parameters.", null);
+        } finally {
+            endpoint.setParentXpath(null);
+            endpoint.setParentLocalName(null);
+        }
+    }
+
+    @Test
+    public void testExceptionXpathsToIdAttributesNameAndXPathSet() throws Exception {
+
+        XmlSignerEndpoint endpoint = getSignatureEncpointForSignException();
+        MockEndpoint mock = setupExceptionMock();
+        try {
+            endpoint.setParentXpath(getNodeSerachXPath());
+            List<XPathFilterParameterSpec> xpaths = Collections.singletonList(XmlSignatureHelper.getXpathFilter("/ns:root/a/@ID", null));
+            endpoint.setXpathsToIdAttributes(xpaths);
+            sendBody("direct:signexceptions", payload);
+            assertMockEndpointsSatisfied();
+            checkThrownException(
+                    mock,
+                    XmlSignatureException.class,
+                    "The configuration of the XML signer component is wrong. " + //
+                            "The parent XPath //pre:root for an enveloped signature and the XPATHs to ID attributes for a detached signature are specified. You must not specify both parameters.",
+                    null);
+        } finally {
+            endpoint.setParentXpath(null);
+            endpoint.setXpathsToIdAttributes(null);
+        }
+    }
+
+    @Test
+    public void testExceptionInvalidParentXpath() throws Exception {
+
+        XmlSignerEndpoint endpoint = getSignatureEncpointForSignException();
+        MockEndpoint mock = setupExceptionMock();
+        try {
+            endpoint.setParentXpath(XmlSignatureHelper.getXpathFilter("//pre:root", null)); // invalid xpath: namespace-prefix mapping is missing
+            sendBody("direct:signexceptions", payload);
+            assertMockEndpointsSatisfied();
+            checkThrownException(mock, XmlSignatureException.class,
+                    "The parent XPath //pre:root is wrongly configured: The XPath //pre:root is invalid.", null);
+        } finally {
+            endpoint.setParentXpath(null);
+        }
+    }
+
+    @Test
+    public void testExceptionParentXpathWithNoResult() throws Exception {
+
+        XmlSignerEndpoint endpoint = getSignatureEncpointForSignException();
+        MockEndpoint mock = setupExceptionMock();
+        try {
+            endpoint.setParentXpath(XmlSignatureHelper.getXpathFilter("//root", null)); // xpath with no result
+            sendBody("direct:signexceptions", payload);
+            assertMockEndpointsSatisfied();
+            checkThrownException(mock, XmlSignatureException.class,
+                    "The parent XPath //root returned no result. Check the configuration of the XML signer component.", null);
+        } finally {
+            endpoint.setParentXpath(null);
+        }
+    }
+
+    XmlSignerEndpoint getSignatureEncpointForSignException() {
+        XmlSignerEndpoint endpoint = (XmlSignerEndpoint) context().getEndpoint("xmlsecurity:sign://signexceptions?keyAccessor=#accessor" + //
+                "&signatureAlgorithm=http://www.w3.org/2001/04/xmldsig-more#rsa-sha512");
+        return endpoint;
+    }
+
+    @Test
+    public void testExceptionParentXpathWithNoElementResult() throws Exception {
+
+        XmlSignerEndpoint endpoint = getSignatureEncpointForSignException();
+        MockEndpoint mock = setupExceptionMock();
+        try {
+            String myPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
+                    "<ns:root ID=\"rootId\" xmlns:ns=\"http://test\"></ns:root>";
+            endpoint.setParentXpath(XmlSignatureHelper.getXpathFilter("/pre:root/@ID", Collections.singletonMap("pre", "http://test"))); // xpath with no element result
+            sendBody("direct:signexceptions", myPayload);
+            assertMockEndpointsSatisfied();
+            checkThrownException(mock, XmlSignatureException.class,
+                    "The parent XPath /pre:root/@ID returned no element. Check the configuration of the XML signer component.", null);
+        } finally {
+            endpoint.setParentXpath(null);
+        }
+    }
+
+    @Test
+    public void testEnvelopedSignatureWithParentXpath() throws Exception {
+        String myPayload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+                + "<ns:root xmlns:ns=\"http://test\"><a>a1</a><a/><test>Test Message</test></ns:root>";
+        setupMock(myPayload);
+        sendBody("direct:envelopedParentXpath", myPayload);
+        assertMockEndpointsSatisfied();
+    }
+
     XmlSignerEndpoint getDetachedSignerEndpoint() {
         XmlSignerEndpoint endpoint = (XmlSignerEndpoint) context().getEndpoint(
                 "xmlsecurity:sign://detached?keyAccessor=#keyAccessorDefault&xpathsToIdAttributes=#xpathsToIdAttributes&"//
@@ -1014,6 +1181,39 @@ public class XmlSignatureTest extends CamelTestSupport {
         return endpoint;
     }
 
+    private void checkOutputEncoding(String inputEncoding, String signerEncoding, String outputEncoding, String signerEndpointUri,
+            String verifierEndpointUri, String directStart) throws InterruptedException, UnsupportedEncodingException {
+        byte[] inputPayload = getPayloadForEncoding(inputEncoding);
+        byte[] expectedPayload = getPayloadForEncoding(outputEncoding);
+
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedBodiesReceived(expectedPayload);
+
+        MockEndpoint mockSigned = getMockEndpoint("mock:signed");
+        mock.expectedMessageCount(1);
+
+        XmlSignerEndpoint endpointSigner = (XmlSignerEndpoint) context().getEndpoint(signerEndpointUri);
+
+        XmlVerifierEndpoint endpoinVerifier = (XmlVerifierEndpoint) context().getEndpoint(verifierEndpointUri);
+        try {
+            endpointSigner.setOutputXmlEncoding(signerEncoding);
+            endpoinVerifier.setOutputXmlEncoding(outputEncoding);
+            sendBody(directStart, inputPayload);
+            assertMockEndpointsSatisfied();
+            Message signedMessage = mockSigned.getExchanges().get(0).getIn();
+            byte[] signedBytes = signedMessage.getBody(byte[].class);
+            String signedPayload = new String(signedBytes, signerEncoding);
+            assertTrue(signedPayload.contains(signerEncoding));
+            String charsetHeaderSigner = signedMessage.getHeader(Exchange.CHARSET_NAME, String.class);
+            assertEquals(signerEncoding, charsetHeaderSigner);
+            String charsetHeaderVerifier = mock.getExchanges().get(0).getIn().getHeader(Exchange.CHARSET_NAME, String.class);
+            assertEquals(outputEncoding, charsetHeaderVerifier);
+        } finally {
+            endpointSigner.setOutputXmlEncoding(null);
+            endpoinVerifier.setOutputXmlEncoding(null);
+        }
+    }
+
     private void checkBodyContains(MockEndpoint mock, String expectedPartContent) {
         Message message = getMessage(mock);
         String body = message.getBody(String.class);
@@ -1350,4 +1550,9 @@ public class XmlSignatureTest extends CamelTestSupport {
         return SameDocumentUriDereferencer.getInstance();
     }
 
+    public static XPathFilterParameterSpec getParentXPathBean() {
+        Map<String, String> prefix2Namespace = Collections.singletonMap("ns", "http://test");
+        return XmlSignatureHelper.getXpathFilter("/ns:root/a[last()]", prefix2Namespace);
+    }
+
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/b8ca2bac/components/camel-xmlsecurity/src/test/resources/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTests.xml
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/test/resources/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTests.xml b/components/camel-xmlsecurity/src/test/resources/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTests.xml
index 96ccd0c..53443a0 100644
--- a/components/camel-xmlsecurity/src/test/resources/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTests.xml
+++ b/components/camel-xmlsecurity/src/test/resources/org/apache/camel/component/xmlsecurity/SpringXmlSignatureTests.xml
@@ -30,6 +30,7 @@
         <route>
             <from uri="direct:enveloping" />
             <to uri="xmlsecurity:sign://enveloping?keyAccessor=#accessorRsa" />
+            <to uri="mock:signed" />
             <to
                 uri="xmlsecurity:verify://enveloping?keySelector=#selectorRsa" />
             <to uri="mock:result" />
@@ -52,6 +53,7 @@
             <from uri="direct:enveloped" />
             <to
                 uri="xmlsecurity:sign://enveloped?keyAccessor=#accessorRsa&amp;parentLocalName=root&amp;parentNamespace=http://test/test" />
+            <to uri="mock:signed" />
             <to
                 uri="xmlsecurity:verify://enveloped?keySelector=#selectorRsa" />
             <to uri="mock:result" />
@@ -270,6 +272,16 @@
         </route>
         <!-- END SNIPPET: detached -->
 
+        <!-- START SNIPPET: enveloped XML signature with parent XPath -->
+        <route>
+            <from uri="direct:envelopedParentXpath" />
+            <to
+                uri="xmlsecurity:sign://enveloped?keyAccessor=#accessorRsa&amp;parentXpath=#parentXpathBean" />
+            <to
+                uri="xmlsecurity:verify://enveloped?keySelector=#selectorRsa" />
+            <to uri="mock:result" />
+        </route>
+        <!-- END SNIPPET: enveloped XML signature with parent XPath -->
 
     </camelContext>
 
@@ -436,4 +448,8 @@
             </list>
         </constructor-arg>
     </bean>
+
+    <bean id="parentXpathBean"
+        class="org.apache.camel.component.xmlsecurity.SpringXmlSignatureTest"
+        factory-method="getParentXPathBean" />
 </beans>