Package org.apache.camel.component.xmlsecurity

Source Code of org.apache.camel.component.xmlsecurity.XmlSignatureTest$SimpleKeySelectorResult

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.xmlsecurity;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
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.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.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 org.w3c.dom.Node;

import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.ProducerTemplate;
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.impl.JndiRegistry;
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\"?>"
        + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";
    private KeyPair keyPair;

    @Override
    protected JndiRegistry createRegistry() throws Exception {
        JndiRegistry registry = super.createRegistry();

        registry.bind("accessor", getKeyAccessor(keyPair.getPrivate()));
        registry.bind("canonicalizationMethod1", getCanonicalizationMethod());
        registry.bind("selector", KeySelector.singletonKeySelector(keyPair.getPublic()));
        registry.bind("selectorKeyValue", getKeyValueKeySelector());
        registry.bind("transformsXPath2", getTransformsXPath2());
        registry.bind("transformsXsltXPath", getTransformsXsltXpath());
        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());

        return registry;
    }

    @Override
    protected RouteBuilder[] createRouteBuilders() throws Exception {
        return new RouteBuilder[] {new RouteBuilder() {
            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")
                    .to("xmlsecurity:verify://enveloping?keySelector=#selector")
                    .to("mock:result");
                // END SNIPPET: enveloping XML signature
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: enveloping XML signature with plain text
                // message body
                onException(XmlSignatureException.class).handled(true).to(
                    "mock:exception");
                from("direct:plaintext")
                    .to("xmlsecurity:sign://plaintext?keyAccessor=#accessor&plainText=true&plainTextEncoding=UTF-8")
                    .to("xmlsecurity:verify://plaintext?keySelector=#selector")
                    .to("mock:result");
                // END SNIPPET: enveloping XML signature with plain text message
                // body
            }
        }, new RouteBuilder() {
            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");
                // END SNIPPET: enveloped XML signature
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: canonicalization
                // we can set the configuration properties explicitly on the
                // endpoint instances.
                context.getEndpoint("xmlsecurity:sign://canonicalization?canonicalizationMethod=#canonicalizationMethod1",
                                    XmlSignerEndpoint.class).setKeyAccessor(getKeyAccessor(keyPair.getPrivate()));
                context.getEndpoint("xmlsecurity:sign://canonicalization?canonicalizationMethod=#canonicalizationMethod1",
                                    XmlSignerEndpoint.class).setSignatureAlgorithm(
                                        "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
                context.getEndpoint("xmlsecurity:verify://canonicalization",
                                    XmlVerifierEndpoint.class).setKeySelector(KeySelector.singletonKeySelector(keyPair.getPublic()));
                from("direct:canonicalization")
                    .to("xmlsecurity:sign://canonicalization?canonicalizationMethod=#canonicalizationMethod1",
                        "xmlsecurity:verify://canonicalization",
                        "mock:result");
                // END SNIPPET: canonicalization
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: signature and digest algorithm
                from("direct:signaturedigestalgorithm")
                    .to("xmlsecurity:sign://signaturedigestalgorithm?keyAccessor=#accessor"
                        + "&signatureAlgorithm=http://www.w3.org/2001/04/xmldsig-more#rsa-sha512&digestAlgorithm=http://www.w3.org/2001/04/xmlenc#sha512",
                        "xmlsecurity:verify://signaturedigestalgorithm?keySelector=#selector")
                    .to("mock:result");
                // END SNIPPET: signature and digest algorithm
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: transforms XPath2
                from("direct:transformsXPath2")
                    .to("xmlsecurity:sign://transformsXPath2?keyAccessor=#accessor&transformMethods=#transformsXPath2",
                        "xmlsecurity:verify://transformsXPath2?keySelector=#selector")
                    .to("mock:result");
                // END SNIPPET: transform XPath
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: transforms XSLT,XPath
                onException(XmlSignatureException.class).handled(false)
                .to("mock:exception");
                from("direct:transformsXsltXPath")
                    .to("xmlsecurity:sign://transformsXsltXPath?keyAccessor=#accessor&transformMethods=#transformsXsltXPath",
                        "xmlsecurity:verify://transformsXsltXPath?keySelector=#selector")
                    .to("mock:result");
                // END SNIPPET: transforms XSLT,XPath
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // 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
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: cryptocontextprops
                onException(XmlSignatureException.class).handled(false).to(
                    "mock:exception");
                from("direct:cryptocontextprops")
                    .to("xmlsecurity:verify://cryptocontextprops?keySelector=#selectorKeyValue&cryptoContextProperties=#cryptoContextProperties")
                    .to("mock:result");
                // END SNIPPET: cryptocontextprops
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: URI dereferencer
                from("direct:uridereferencer")
                    .to("xmlsecurity:sign://uriderferencer?keyAccessor=#accessor&uriDereferencer=#uriDereferencer")
                    .to("xmlsecurity:verify://uridereferencer?keySelector=#selector&uriDereferencer=#uriDereferencer")
                    .to("mock:result");
                // END SNIPPET: URI dereferencer
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: keyAccessorKeySelectorDefault
                from("direct:keyAccessorKeySelectorDefault")
                    .to("xmlsecurity:sign://keyAccessorKeySelectorDefault?keyAccessor=#keyAccessorDefault&addKeyInfoReference=true")
                    .to("xmlsecurity:verify://keyAccessorKeySelectorDefault?keySelector=#keySelectorDefault")
                    .to("mock:result");
                // END SNIPPET: keyAccessorKeySelectorDefault
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: xmlSignatureChecker
                onException(XmlSignatureInvalidException.class).handled(false).to("mock:exception");
                from("direct:xmlSignatureChecker")
                    .to("xmlsecurity:verify://xmlSignatureChecker?keySelector=#selectorKeyValue&xmlSignatureChecker=#envelopingSignatureChecker")
                    .to("mock:result");
                // END SNIPPET: xmlSignatureChecker
            }
        }, new RouteBuilder() {
            public void configure() throws Exception { //
                // START SNIPPET: properties
                from("direct:props")
                    .to("xmlsecurity:sign://properties?keyAccessor=#accessor&properties=#signatureProperties")
                    .to("xmlsecurity:verify://properties?keySelector=#selector&xmlSignature2Message=#xmlSignature2MessageWithTimestampProperty")
                    .to("mock:result");
                // END SNIPPET: properties
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: verify output node search element name
                onException(XmlSignatureException.class).handled(true).to(
                    "mock:exception");
                from("direct:outputnodesearchelementname")
                    .to("xmlsecurity:verify://outputnodesearchelementname?keySelector=#selectorKeyValue"
                        + "&outputNodeSearchType=ElementName&outputNodeSearch={http://test/test}root&removeSignatureElements=true")
                    .to("mock:result");
                // END SNIPPET: verify output node search element name
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: verify output node search xpath
                onException(XmlSignatureException.class).handled(true).to(
                    "mock:exception");
                from("direct:outputnodesearchxpath")
                    .to("xmlsecurity:verify://outputnodesearchxpath?keySelector=#selectorKeyValue&outputNodeSearchType=XPath&outputNodeSearch=#nodesearchxpath&removeSignatureElements=true")
                    .to("mock:result");
                // END SNIPPET: verify output node search xpath
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: validationFailedHandler
                from("direct:validationFailedHandler")
                    .to("xmlsecurity:verify://validationFailedHandler?keySelector=#selectorKeyValue&validationFailedHandler=validationFailedHandlerIgnoreManifestFailures")
                    .to("mock:result");
                // END SNIPPET: validationFailedHandler
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: further parameters
                from("direct:furtherparams")
                    .to("xmlsecurity:sign://furtherparams?keyAccessor=#accessor&prefixForXmlSignatureNamespace=digsig&disallowDoctypeDecl=false")
                    .to("xmlsecurity:verify://bfurtherparams?keySelector=#selector&disallowDoctypeDecl=false")
                    .to("mock:result");
                // END SNIPPET: further parameters
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: signer invalid keyexception
                onException(XmlSignatureInvalidKeyException.class).handled(true).to("mock:exception");
                from("direct:signexceptioninvalidkey")
                    .to("xmlsecurity:sign://signexceptioninvalidkey?signatureAlgorithm=http://www.w3.org/2001/04/xmldsig-more#rsa-sha512")
                    .to("mock:result");
                // END SNIPPET: signer invalid keyexception
            }
        }, new RouteBuilder() {
            public void configure() throws Exception {
                // START SNIPPET: signer exceptions
                onException(XmlSignatureException.class).handled(true).to("mock:exception");
                from("direct:signexceptions")
                    .to("xmlsecurity:sign://signexceptions?keyAccessor=#accessor&signatureAlgorithm=http://www.w3.org/2001/04/xmldsig-more#rsa-sha512")
                    .to("mock:result");
                // END SNIPPET: signer exceptions
            }
        }, 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
            }
        }

        };
    }

    @Test
    public void testEnvelopingSignature() throws Exception {
        setupMock();
        sendBody("direct:enveloping", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testEnvelopingSignatureWithPlainText() throws Exception {
        String text = "plain test text";
        setupMock(text);
        sendBody("direct:plaintext", text);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testEnvelopingSignatureWithPlainTextSetByHeaders()
        throws Exception {
        String text = "plain test text";
        setupMock(text);
        Map<String, Object> headers = new TreeMap<String, Object>();
        headers.put(XmlSignatureConstants.HEADER_MESSAGE_IS_PLAIN_TEXT,
                    Boolean.TRUE);
        headers.put(XmlSignatureConstants.HEADER_PLAIN_TEXT_ENCODING, "UTF-8");
        sendBody("direct:enveloping", text, headers);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testExceptionSignatureForPlainTextWithWrongEncoding()
        throws Exception {
        String text = "plain test text";
        MockEndpoint mock = setupExceptionMock();
        Map<String, Object> headers = new TreeMap<String, Object>();
        headers.put(XmlSignatureConstants.HEADER_MESSAGE_IS_PLAIN_TEXT,
                    Boolean.TRUE);
        headers.put(XmlSignatureConstants.HEADER_PLAIN_TEXT_ENCODING,
            "wrongEncoding");
        sendBody("direct:enveloping", text, headers);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class,
                             UnsupportedEncodingException.class);
    }

    @Test
    public void testEnvelopedSignature() throws Exception {
        setupMock(payload);
        sendBody("direct:enveloped", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testExceptionEnvelopedSignatureWithWrongParent()
        throws Exception {
        // payload root element renamed to a -> parent name in route definition
        // does not fit
        String payload = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a xmlns=\"http://test/test\"><test>Test Message</test></a>";

        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:enveloped", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    @Test
    public void testExceptionEnvelopedSignatureWithPlainTextPayload()
        throws Exception {
        // payload root element renamed to a -> parent name in route definition
        // does not fit
        String payload = "plain text Message";
        Map<String, Object> headers = new HashMap<String, Object>(1);
        headers.put(XmlSignatureConstants.HEADER_MESSAGE_IS_PLAIN_TEXT,
                    Boolean.TRUE);
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:enveloped", payload, headers);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    /**
     * The parameter can also be configured via
     * {@link XmlSignatureConfiguration#setOmitXmlDeclaration(Boolean)}
     */
    @Test
    public void testOmitXmlDeclarationViaHeader() throws Exception {
        String payloadOut = "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";
        setupMock(payloadOut);
        Map<String, Object> headers = new TreeMap<String, Object>();
        headers.put(XmlSignatureConstants.HEADER_OMIT_XML_DECLARATION,
                    Boolean.TRUE);
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload, headers);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testkeyAccessorKeySelectorDefault() throws Exception {
        setupMock();
        sendBody("direct:keyAccessorKeySelectorDefault", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testSetCanonicalizationMethodInRouteDefinition()
        throws Exception {
        setupMock();
        sendBody("direct:canonicalization", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testSetDigestAlgorithmInRouteDefinition() throws Exception {

        setupMock();
        sendBody("direct:signaturedigestalgorithm", payload);
        assertMockEndpointsSatisfied();
    }

    @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\"?>"
            + "<Document xmlns=\"http://test/test\">                             "
            + "<ToBeSigned>                                                     "
            + "   <!-- comment -->                                              "
            + "   <Data>1</Data>                                                "
            + "   <NotToBeSigned>                                               "
            + "     <ReallyToBeSigned>                                          "
            + "       <!-- comment -->                                          "
            + "       <Data>2</Data>                                            "
            + "     </ReallyToBeSigned>                                         "
            + "   </NotToBeSigned>                                              "
            + " </ToBeSigned>                                                   "
            + " <ToBeSigned>                                                    "
            + "   <Data>3</Data>                                                "
            + "   <NotToBeSigned>                                               "
            + "     <Data>4</Data>                                              "
            + "   </NotToBeSigned>                                              "
            + " </ToBeSigned>                                                   "
            + "</Document>";

        setupMock(payload);
        sendBody("direct:transformsXPath2", payload);
        assertMockEndpointsSatisfied();
    }

    // Secure Validation is enabled and so this should fail
    @Test
    public void testSetTransformMethodXsltXpathInRouteDefinition()
        throws Exception {
        // byte[] encoded = Base64.encode("Test Message".getBytes("UTF-8"));
        // String contentBase64 = new String(encoded, "UTF-8");
        // String payload =
        // "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root xmlns=\"http://test/test\"><test></test></root>";
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:transformsXsltXPath", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }
   
    @Test
    public void testSetTransformMethodXsltXpathInRouteDefinitionSecValDisabled()
        throws Exception {
        setupMock();
        sendBody("direct:transformsXsltXPathSecureValDisabled", payload);
        assertMockEndpointsSatisfied();
    }
   
    @Test
    public void testProperties() throws Exception {
        setupMock();
        sendBody("direct:props", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testVerifyOutputNodeSearchElementName() throws Exception {
        setupMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testVerifyExceptionOutputNodeSearchElementNameInvalidFormat1()
        throws Exception {
        XmlVerifierEndpoint endpoint = context
            .getEndpoint(
                         "xmlsecurity:verify://outputnodesearchelementname?keySelector=#selectorKeyValue"
                         + "&outputNodeSearchType=ElementName&outputNodeSearch={http://test/test}root&removeSignatureElements=true",
                         XmlVerifierEndpoint.class);
        endpoint.setOutputNodeSearch("{wrongformat"); // closing '}' missing
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testVerifyExceptionOutputNodeSearchElementNameInvalidFormat2()
        throws Exception {
        context.getEndpoint("xmlsecurity:verify://outputnodesearchelementname?keySelector=#selectorKeyValue"
                            + "&outputNodeSearchType=ElementName&outputNodeSearch={http://test/test}root&removeSignatureElements=true",
                            XmlVerifierEndpoint.class).setOutputNodeSearch("{wrongformat}");
        // local name missing
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testExceptionVerifyOutputNodeSearchWrongElementName()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testExceptionVerifyOutputNodeSearchElementNameMoreThanOneOutputElement()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSigWithSeveralElementsWithNameRoot.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchelementname", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testVerifyOutputNodeSearchXPath() throws Exception {
        setupMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchxpath", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testExceptionVerifyOutputNodeSearchXPathWithNoResultNode()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchxpath", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testExceptionVerifyOutputNodeSearchXPathMoreThanOneOutputElement()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSigWithSeveralElementsWithNameRoot.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:outputnodesearchxpath", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, null);
    }

    @Test
    public void testInvalidKeyException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        // wrong key type
        setUpKeys("DSA", 512);
        context.getEndpoint("xmlsecurity:sign://signexceptioninvalidkey?signatureAlgorithm=http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
                            XmlSignerEndpoint.class).setKeyAccessor(getKeyAccessor(keyPair.getPrivate()));
        sendBody("direct:signexceptioninvalidkey", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidKeyException.class, null);
    }

    @Test
    public void testSignatureFormatException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:signexceptions", "wrongFormatedPayload");
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    @Test
    public void testNoSuchAlgorithmException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:noSuchAlgorithmException", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureException.class, NoSuchAlgorithmException.class);
    }

    @Test
    public void testVerifyFormatExceptionNoXml() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:verifyexceptions", "wrongFormatedPayload");
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    @Test
    public void testVerifyFormatExceptionNoXmlWithoutSignatureElement()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:verifyexceptions",
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><NoSignature></NoSignature>");
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    @Test
    public void testVerifyFormatExceptionMoreThanOneSignatureElement()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        sendBody("direct:verifyexceptions",
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"/><Signature xmlns=\"http://www.w3.org/2000/09/xmldsig#\"/></root>");
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureFormatException.class, null);
    }

    @Test
    public void testVerifyInvalidContentHashException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleDetached.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:invalidhash", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidContentHashException.class, null);
    }

    @Test
    public void testVerifyMantifestInvalidContentHashException()
        throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ManifestTest_TamperedContent.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:invalidhash", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidContentHashException.class, null);
    }

    @Test
    public void testVerifySetCryptoContextProperties() throws Exception {
        // although the content referenced by the manifest was tempered, this is
        // not detected by
        // the core validation because the manifest validation is switched off
        // by the crypto context properties
        setupMock("some text tampered");
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ManifestTest_TamperedContent.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:cryptocontextprops", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testVerifySignatureInvalidValueException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        setUpKeys("DSA", 512);
        context.getEndpoint("xmlsecurity:verify://verifyexceptions?keySelector=#selector",
                            XmlVerifierEndpoint.class).setKeySelector(KeySelector.singletonKeySelector(keyPair.getPublic()));
        // payload needs DSA key
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:verifyexceptions", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidValueException.class, null);
    }

    @Test
    public void testVerifyInvalidKeyException() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopingDigSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:verifyInvalidKeyException", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidKeyException.class, null);
    }

    @Test
    public void testUriDereferencerAndBaseUri() throws Exception {
        setupMock();
        sendBody("direct:uridereferencer", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testVerifyXmlSignatureChecker() throws Exception {
        MockEndpoint mock = setupExceptionMock();
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ExampleEnvelopedXmlSig.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:xmlSignatureChecker", payload);
        assertMockEndpointsSatisfied();
        checkThrownException(mock, XmlSignatureInvalidException.class, null);
    }

    @Test
    public void testVerifyValidationFailedHandler() throws Exception {
        setupMock("some text tampered");
        InputStream payload = XmlSignatureTest.class
            .getResourceAsStream("/org/apache/camel/component/xmlsecurity/ManifestTest_TamperedContent.xml");
        assertNotNull("Cannot load payload", payload);
        sendBody("direct:validationFailedHandler", payload);
        assertMockEndpointsSatisfied();
    }

    @Test
    public void testFurtherParameters() throws Exception {
        setupMock(payload);
        String payloadWithDTDoctype = "<?xml version=\'1.0\'?>"
            + "<!DOCTYPE Signature SYSTEM "
            + "\"src/test/resources/org/apache/camel/component/xmlsecurity/xmldsig-core-schema.dtd\" [ <!ENTITY dsig "
            + "\"http://www.w3.org/2000/09/xmldsig#\"> ]>"
            + "<root xmlns=\"http://test/test\"><test>Test Message</test></root>";

        sendBody("direct:furtherparams", payloadWithDTDoctype);
        assertMockEndpointsSatisfied();
    }

    private void checkThrownException(MockEndpoint mock,
                                      Class<? extends XmlSignatureException> cl,
                                      Class<? extends Exception> expectedCauseClass) throws Exception {
        Exception e = (Exception) mock.getExchanges().get(0)
            .getProperty(Exchange.EXCEPTION_CAUGHT);
        assertNotNull("Expected excpetion " + cl.getName() + " missing", e);
        if (e.getClass() != cl) {
            String stackTrace = getStrackTrace(e);
            fail("Exception  " + cl.getName() + " excpected, but was "
                + e.getClass().getName() + ": " + stackTrace);
        }
        if (expectedCauseClass != null) {
            Throwable cause = e.getCause();
            assertNotNull(
                          "Expected cause exception" + expectedCauseClass.getName()
                          + " missing", cause);
            if (expectedCauseClass != cause.getClass()) {
                fail("Cause exception " + expectedCauseClass.getName()
                     + " expected, but was " + cause.getClass().getName()
                     + ": " + getStrackTrace(e));
            }
        }
    }

    private String getStrackTrace(Exception e)
        throws UnsupportedEncodingException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter w = new PrintWriter(os);
        e.printStackTrace(w);
        w.close();
        String stackTrace = new String(os.toByteArray(), "UTF-8");
        return stackTrace;
    }

    private MockEndpoint setupExceptionMock() {
        MockEndpoint mock = getMockEndpoint("mock:exception");
        mock.setExpectedMessageCount(1);
        MockEndpoint mockResult = getMockEndpoint("mock:result");
        mockResult.setExpectedMessageCount(0);
        return mock;
    }

    private MockEndpoint setupMock() {
        return setupMock(payload);
    }

    private MockEndpoint setupMock(String payload) {
        MockEndpoint mock = getMockEndpoint("mock:result");
        mock.expectedBodiesReceived(payload);
        return mock;
    }

    public Exchange doTestSignatureRoute(RouteBuilder builder) throws Exception {
        return doSignatureRouteTest(builder, null, Collections.<String, Object>emptyMap());
    }

    public Exchange doSignatureRouteTest(RouteBuilder builder, Exchange e,
                                         Map<String, Object> headers) throws Exception {
        CamelContext context = new DefaultCamelContext();
        try {
            context.addRoutes(builder);
            context.start();

            MockEndpoint mock = context.getEndpoint("mock:result",
                                                    MockEndpoint.class);
            mock.setExpectedMessageCount(1);

            ProducerTemplate template = context.createProducerTemplate();
            if (e != null) {
                template.send("direct:in", e);
            } else {
                template.sendBodyAndHeaders("direct:in", payload, headers);
            }
            assertMockEndpointsSatisfied();
            return mock.getReceivedExchanges().get(0);
        } finally {
            context.stop();
        }
    }

    @Before
    public void setUp() throws Exception {
        setUpKeys("RSA", 1024);
        disableJMX();
        super.setUp();
    }

    public void setUpKeys(String algorithm, int keylength) throws Exception {
        keyPair = getKeyPair(algorithm, keylength);
    }

    public static KeyPair getKeyPair(String algorithm, int keylength) {
        KeyPairGenerator keyGen;
        try {
            keyGen = KeyPairGenerator.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        keyGen.initialize(keylength, new SecureRandom());
        return keyGen.generateKeyPair();
    }

    public static KeyStore loadKeystore() throws Exception {
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        InputStream in = XmlSignatureTest.class.getResourceAsStream("/bob.keystore");
        keystore.load(in, "letmein".toCharArray());
        return keystore;
    }

    public Certificate getCertificateFromKeyStore() throws Exception {
        Certificate c = loadKeystore().getCertificate("bob");
        return c;
    }

    public PrivateKey getKeyFromKeystore() throws Exception {
        return (PrivateKey) loadKeystore().getKey("bob",
                                                  "letmein".toCharArray());
    }

    private AlgorithmMethod getCanonicalizationMethod() {
        List<String> inclusivePrefixes = new ArrayList<String>(1);
        inclusivePrefixes.add("ds");
        return XmlSignatureHelper.getCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, inclusivePrefixes);
    }

    private List<AlgorithmMethod> getTransformsXPath2() {

        List<XPathAndFilter> list = new ArrayList<XPathAndFilter>(3);
        XPathAndFilter xpath1 = new XPathAndFilter("//n0:ToBeSigned",
                                                   XPathType.Filter.INTERSECT.toString());
        list.add(xpath1);
        XPathAndFilter xpath2 = new XPathAndFilter("//n0:NotToBeSigned",
                                                   XPathType.Filter.SUBTRACT.toString());
        list.add(xpath2);
        XPathAndFilter xpath3 = new XPathAndFilter("//n0:ReallyToBeSigned",
                                                   XPathType.Filter.UNION.toString());
        list.add(xpath3);
        List<AlgorithmMethod> result = new ArrayList<AlgorithmMethod>(2);
        result.add(XmlSignatureHelper
                   .getCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE));
        result.add(XmlSignatureHelper.getXPath2Transform(list, getNamespaceMap()));
        return result;
    }

    private Map<String, String> getNamespaceMap() {
        Map<String, String> result = new HashMap<String, String>(1);
        result.put("n0", "http://test/test");
        return result;
    }

    private List<AlgorithmMethod> getTransformsXsltXpath() {
        try {
            AlgorithmMethod transformXslt = XmlSignatureHelper
                .getXslTransform("/org/apache/camel/component/xmlsecurity/xslt_test.xsl");
            Map<String, String> namespaceMap = new HashMap<String, String>(1);
            namespaceMap.put("n0", "https://org.apache/camel/xmlsecurity/test");
            AlgorithmMethod transformXpath = XmlSignatureHelper
                .getXPathTransform("//n0:XMLSecurity/n0:Content",
                                   namespaceMap);
            // I removed base 64 transform because the JDK implementation does
            // not correctly support this transformation
            // AlgorithmMethod transformBase64 = helper.getBase64Transform();
            List<AlgorithmMethod> result = new ArrayList<AlgorithmMethod>(3);
            result.add(XmlSignatureHelper
                       .getCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE));
            result.add(transformXslt);
            result.add(transformXpath);
            // result.add(transformBase64);
            return result;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    static KeyAccessor getKeyAccessor(final PrivateKey privateKey) {
        KeyAccessor accessor = new KeyAccessor() {

            @Override
            public KeySelector getKeySelector(Message message) throws Exception {
                return KeySelector.singletonKeySelector(privateKey);
            }

            @Override
            public KeyInfo getKeyInfo(Message mess, Node messageBody,
                                      KeyInfoFactory keyInfoFactory) throws Exception {
                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 {
        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;
        }

        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();
    }

}
TOP

Related Classes of org.apache.camel.component.xmlsecurity.XmlSignatureTest$SimpleKeySelectorResult

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.