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 <[email protected]> Authored: Tue Sep 16 20:20:58 2014 +0800 Committer: Willem Jiang <[email protected]> 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&parentLocalName=root&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&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>
