This is an automated email from the ASF dual-hosted git repository. acosentino pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit b0c29def3247be6503157a8aa8b4d986068c2e08 Author: Andrea Cosentino <[email protected]> AuthorDate: Fri Jan 13 13:30:56 2023 +0100 Camel-XML-Security: Fixed tests after Jakarta migration Signed-off-by: Andrea Cosentino <[email protected]> --- .../xmlsecurity/SpringXmlSignatureTest.java | 289 +++++++++++++++++++-- 1 file changed, 268 insertions(+), 21 deletions(-) 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 738ae09c028..94b80a1e6ec 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 @@ -16,30 +16,292 @@ */ package org.apache.camel.component.xmlsecurity; -import java.io.ByteArrayInputStream; +import java.io.*; +import java.nio.charset.Charset; +import java.security.Key; +import java.security.KeyException; import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.TreeMap; +import javax.xml.crypto.AlgorithmMethod; import javax.xml.crypto.KeySelector; +import javax.xml.crypto.KeySelectorException; +import javax.xml.crypto.KeySelectorResult; +import javax.xml.crypto.URIDereferencer; +import javax.xml.crypto.XMLCryptoContext; +import javax.xml.crypto.XMLStructure; +import javax.xml.crypto.dsig.CanonicalizationMethod; +import javax.xml.crypto.dsig.SignatureMethod; +import javax.xml.crypto.dsig.XMLSignature; +import javax.xml.crypto.dsig.keyinfo.KeyInfo; +import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; +import javax.xml.crypto.dsig.keyinfo.KeyValue; +import javax.xml.crypto.dsig.spec.XPathFilterParameterSpec; +import javax.xml.crypto.dsig.spec.XPathType; +import javax.xml.namespace.NamespaceContext; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import org.apache.camel.spring.SpringCamelContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.w3c.dom.Attr; import org.w3c.dom.Document; +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; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.RuntimeCamelException; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.mock.MockEndpoint; import org.apache.camel.component.xmlsecurity.api.KeyAccessor; +import org.apache.camel.component.xmlsecurity.api.ValidationFailedHandler; +import org.apache.camel.component.xmlsecurity.api.XmlSignature2Message; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureChecker; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureConstants; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureException; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureFormatException; import org.apache.camel.component.xmlsecurity.api.XmlSignatureHelper; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureHelper.XPathAndFilter; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureInvalidContentHashException; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureInvalidException; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureInvalidKeyException; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureInvalidValueException; +import org.apache.camel.component.xmlsecurity.api.XmlSignatureProperties; +import org.apache.camel.component.xmlsecurity.processor.XmlSignatureConfiguration; +import org.apache.camel.component.xmlsecurity.util.EnvelopingXmlSignatureChecker; +import org.apache.camel.component.xmlsecurity.util.SameDocumentUriDereferencer; +import org.apache.camel.component.xmlsecurity.util.TestKeystore; +import org.apache.camel.component.xmlsecurity.util.TimestampProperty; +import org.apache.camel.component.xmlsecurity.util.ValidationFailedHandlerIgnoreManifestFailures; +import org.apache.camel.component.xmlsecurity.util.XmlSignature2Message2MessageWithTimestampProperty; +import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.spi.Registry; -import org.apache.camel.spring.SpringCamelContext; import org.apache.camel.support.SimpleRegistry; +import org.apache.camel.support.processor.validation.SchemaValidationException; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.springframework.context.support.ClassPathXmlApplicationContext; -public class SpringXmlSignatureTest extends XmlSignatureTest { +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class SpringXmlSignatureTest extends CamelTestSupport { + + protected static String payload; + private static boolean includeNewLine; + private KeyPair keyPair; private static KeyPair rsaPair; + static { + payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + (includeNewLine ? "\n" : "") + + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>"; + } + + @Override + protected Registry createCamelRegistry() throws Exception { + Registry registry = new SimpleRegistry(); + + registry.bind("accessor", getKeyAccessor(keyPair.getPrivate())); + registry.bind("selector", KeySelector.singletonKeySelector(keyPair.getPublic())); + registry.bind("selectorKeyValue", getKeyValueKeySelector()); + registry.bind("uriDereferencer", getSameDocumentUriDereferencer()); + registry.bind("baseUri", getBaseUri()); + registry.bind("cryptoContextProperties", getCrytoContextProperties()); + registry.bind("keyAccessorDefault", getDefaultKeyAccessor()); + registry.bind("keySelectorDefault", getDefaultKeySelector()); + registry.bind("envelopingSignatureChecker", getEnvelopingXmlSignatureChecker()); + registry.bind("xmlSignature2MessageWithTimestampProperty", getXmlSignature2MessageWithTimestampdProperty()); + registry.bind("validationFailedHandlerIgnoreManifestFailures", getValidationFailedHandlerIgnoreManifestFailures()); + registry.bind("signatureProperties", getSignatureProperties()); + registry.bind("nodesearchxpath", getNodeSerachXPath()); + Map<String, String> namespaceMap = Collections.singletonMap("ns", "http://test"); + List<XPathFilterParameterSpec> xpaths = Collections + .singletonList(XmlSignatureHelper.getXpathFilter("/ns:root/a/@ID", namespaceMap)); + registry.bind("xpathsToIdAttributes", xpaths); + + registry.bind("parentXpathBean", getParentXPathBean()); + + return registry; + } + + Message getMessage(MockEndpoint mock) { + List<Exchange> exs = mock.getExchanges(); + assertNotNull(exs); + assertEquals(1, exs.size()); + Exchange ex = exs.get(0); + Message mess = ex.getIn(); + assertNotNull(mess); + return mess; + } + + public static KeyPair getKeyPair(String algorithm, int keylength) { + KeyPairGenerator keyGen; + try { + keyGen = KeyPairGenerator.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeCamelException(e); + } + keyGen.initialize(keylength, new SecureRandom()); + return keyGen.generateKeyPair(); + } + + static KeyAccessor getKeyAccessor(final PrivateKey privateKey) { + KeyAccessor accessor = new KeyAccessor() { + + @Override + public KeySelector getKeySelector(Message message) { + return KeySelector.singletonKeySelector(privateKey); + } + + @Override + public KeyInfo getKeyInfo(Message mess, Node messageBody, KeyInfoFactory keyInfoFactory) { + return null; + } + }; + return accessor; + } + + public static String getBaseUri() { + String uri = "file:/" + System.getProperty("user.dir") + "/src/test/resources/org/apache/camel/component/xmlsecurity/"; + return uri.replace('\\', '/'); + } + + public static KeySelector getKeyValueKeySelector() { + return new KeyValueKeySelector(); + } + + /** + * KeySelector which retrieves the public key from the KeyValue element and returns it. NOTE: If the key algorithm + * doesn't match signature algorithm, then the public key will be ignored. + */ + static class KeyValueKeySelector extends KeySelector { + @Override + public KeySelectorResult select( + KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) + throws KeySelectorException { + if (keyInfo == null) { + throw new KeySelectorException("Null KeyInfo object!"); + } + + SignatureMethod sm = (SignatureMethod) method; + @SuppressWarnings("rawtypes") + List list = keyInfo.getContent(); + + for (int i = 0; i < list.size(); i++) { + XMLStructure xmlStructure = (XMLStructure) list.get(i); + if (xmlStructure instanceof KeyValue) { + PublicKey pk = null; + try { + pk = ((KeyValue) xmlStructure).getPublicKey(); + } catch (KeyException ke) { + throw new KeySelectorException(ke); + } + // make sure algorithm is compatible with method + if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) { + return new SimpleKeySelectorResult(pk); + } + } + } + throw new KeySelectorException("No KeyValue element found!"); + } + + static boolean algEquals(String algURI, String algName) { + return algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1) + || algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1); + } + } + + private static class SimpleKeySelectorResult implements KeySelectorResult { + private PublicKey pk; + + SimpleKeySelectorResult(PublicKey pk) { + this.pk = pk; + } + + @Override + public Key getKey() { + return pk; + } + } + + public static Map<String, ? extends Object> getCrytoContextProperties() { + return Collections.singletonMap("org.jcp.xml.dsig.validateManifests", Boolean.FALSE); + } + + public static KeyAccessor getDefaultKeyAccessor() throws Exception { + return TestKeystore.getKeyAccessor("bob"); + } + + public static KeySelector getDefaultKeySelector() throws Exception { + return TestKeystore.getKeySelector("bob"); + } + + public static KeyAccessor getDefaultKeyAccessorDsa() throws Exception { + return TestKeystore.getKeyAccessor("bobdsa"); + } + + public static KeySelector getDefaultKeySelectorDsa() throws Exception { + return TestKeystore.getKeySelector("bobdsa"); + } + + public static XmlSignatureChecker getEnvelopingXmlSignatureChecker() { + return new EnvelopingXmlSignatureChecker(); + } + + public static XmlSignature2Message getXmlSignature2MessageWithTimestampdProperty() { + return new XmlSignature2Message2MessageWithTimestampProperty(); + } + + public static ValidationFailedHandler getValidationFailedHandlerIgnoreManifestFailures() { + return new ValidationFailedHandlerIgnoreManifestFailures(); + } + + public static XmlSignatureProperties getSignatureProperties() { + return new TimestampProperty(); + } + + public static XPathFilterParameterSpec getNodeSerachXPath() { + Map<String, String> prefix2Namespace = Collections.singletonMap("pre", "http://test/test"); + return XmlSignatureHelper.getXpathFilter("//pre:root", prefix2Namespace); + } + + public static URIDereferencer getSameDocumentUriDereferencer() { + return SameDocumentUriDereferencer.getInstance(); + } + + public static XPathFilterParameterSpec getParentXPathBean() { + Map<String, String> prefix2Namespace = Collections.singletonMap("ns", "http://test"); + return XmlSignatureHelper.getXpathFilter("/ns:root/a[last()]", prefix2Namespace); + } + @Override protected CamelContext createCamelContext() throws Exception { rsaPair = getKeyPair("RSA", 1024); @@ -64,48 +326,32 @@ public class SpringXmlSignatureTest extends XmlSignatureTest { return KeySelector.singletonKeySelector(rsaPair.getPublic()); } - @Override - protected Registry createCamelRegistry() { - return new SimpleRegistry(); - } - - @Override - protected RouteBuilder[] createRouteBuilders() { - return new RouteBuilder[] {}; - } - - @Override XmlSignerEndpoint getDetachedSignerEndpoint() { XmlSignerEndpoint endpoint = (XmlSignerEndpoint) context() .getEndpoint( "xmlsecurity-sign:detached?keyAccessor=#accessorRsa&xpathsToIdAttributes=#xpathsToIdAttributes&"// - + "schemaResourceUri=org/apache/camel/component/xmlsecurity/Test.xsd&signatureId=&clearHeaders=false"); + + "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 getVerifierEndpointURIEnveloping() { return "xmlsecurity-verify:enveloping?keySelector=#selectorRsa"; } - @Override String getSignerEndpointURIEnveloping() { return "xmlsecurity-sign:enveloping?keyAccessor=#accessorRsa"; } @@ -128,4 +374,5 @@ public class SpringXmlSignatureTest extends XmlSignatureTest { "/ds:Signature/ds:Object/etsi:QualifyingProperties/etsi:SignedProperties/etsi:SignedSignatureProperties/etsi:SignerRole/etsi:ClaimedRoles/etsi:ClaimedRole/t:test", prefix2Ns, "test"); } + }
