You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by co...@apache.org on 2012/06/29 13:16:21 UTC

svn commit: r1355316 - in /santuario/xml-security-java/trunk/src: main/java/org/apache/xml/security/stax/ext/ main/java/org/apache/xml/security/stax/impl/processor/output/ test/java/org/apache/xml/security/test/dom/ test/java/org/apache/xml/security/te...

Author: coheigea
Date: Fri Jun 29 11:16:19 2012
New Revision: 1355316

URL: http://svn.apache.org/viewvc?rev=1355316&view=rev
Log:
[SANTUARIO-316] - Added initial outbound processors for streaming Signature + a basic testcase

Added:
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureOutputProcessor.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/SignatureTest.java
Modified:
    santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/ext/AbstractOutputProcessor.java
    santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/DSNamespaceContext.java

Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/ext/AbstractOutputProcessor.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/ext/AbstractOutputProcessor.java?rev=1355316&r1=1355315&r2=1355316&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/ext/AbstractOutputProcessor.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/ext/AbstractOutputProcessor.java Fri Jun 29 11:16:19 2012
@@ -126,7 +126,8 @@ public abstract class AbstractOutputProc
         for (int i = 0; i < attributeList.size(); i++) {
             XMLSecAttribute xmlSecAttribute = attributeList.get(i);
             final QName attributeName = xmlSecAttribute.getName();
-            if (attributeName.getNamespaceURI() != null && !declaredNamespaces.contains(xmlSecAttribute.getAttributeNamespace())) {
+            if (attributeName.getNamespaceURI() != null && !"".equals(attributeName.getNamespaceURI()) 
+                && !declaredNamespaces.contains(xmlSecAttribute.getAttributeNamespace())) {
                 declaredNamespaces.add(xmlSecAttribute.getAttributeNamespace());
             }
         }

Added: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java?rev=1355316&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java (added)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java Fri Jun 29 11:16:19 2012
@@ -0,0 +1,178 @@
+/**
+ * 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.xml.security.stax.impl.processor.output;
+
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+
+import org.apache.xml.security.stax.ext.AbstractBufferingOutputProcessor;
+import org.apache.xml.security.stax.ext.OutputProcessorChain;
+import org.apache.xml.security.stax.ext.SecurityToken;
+import org.apache.xml.security.stax.ext.XMLSecurityConstants;
+import org.apache.xml.security.stax.ext.XMLSecurityException;
+import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
+import org.apache.xml.security.stax.ext.stax.XMLSecEndElement;
+import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
+import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
+import org.apache.xml.security.stax.impl.SignaturePartDef;
+import org.apache.xml.security.stax.impl.algorithms.SignatureAlgorithm;
+
+/**
+ * An EndingOutputProcessor for XML Signature.
+ */
+public class XMLSignatureEndingOutputProcessor extends AbstractSignatureEndingOutputProcessor {
+
+    private SignedInfoProcessor signedInfoProcessor = null;
+
+    public XMLSignatureEndingOutputProcessor(XMLSignatureOutputProcessor signatureOutputProcessor) throws XMLSecurityException {
+        super(signatureOutputProcessor);
+        this.addAfterProcessor(XMLSignatureOutputProcessor.class.getName());
+    }
+
+    @Override
+    public void doFinal(OutputProcessorChain outputProcessorChain) throws XMLStreamException, XMLSecurityException {
+        setAppendAfterThisTokenId(outputProcessorChain.getSecurityContext().<String>get(XMLSecurityConstants.PROP_APPEND_SIGNATURE_ON_THIS_ID));
+        OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
+        flushBufferAndCallbackAfterTokenID(subOutputProcessorChain, this, getXmlSecEventBuffer());
+        //call final on the rest of the chain
+        subOutputProcessorChain.doFinal();
+        //this processor is now finished and we can remove it now
+        subOutputProcessorChain.removeProcessor(this);
+    }
+
+    @Override
+    protected SignedInfoProcessor newSignedInfoProcessor(SignatureAlgorithm signatureAlgorithm, OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
+        this.signedInfoProcessor = new SignedInfoProcessor(signatureAlgorithm);
+        this.signedInfoProcessor.setXMLSecurityProperties(getSecurityProperties());
+        this.signedInfoProcessor.setAction(getAction());
+        this.signedInfoProcessor.addAfterProcessor(XMLSignatureEndingOutputProcessor.class.getName());
+        this.signedInfoProcessor.init(outputProcessorChain);
+        return this.signedInfoProcessor;
+    }
+
+    @Override
+    protected void createKeyInfoStructureForSignature(
+            OutputProcessorChain outputProcessorChain,
+            SecurityToken securityToken,
+            boolean useSingleCertificate)
+            throws XMLStreamException, XMLSecurityException {
+        // Issuer-Serial by default
+        X509Certificate[] x509Certificates = securityToken.getX509Certificates();
+        if (x509Certificates != null) {
+            createX509IssuerSerialStructure(outputProcessorChain, x509Certificates);
+        }
+    }
+
+    @Override
+    protected void createTransformsStructureForSignature(OutputProcessorChain subOutputProcessorChain, SignaturePartDef signaturePartDef) throws XMLStreamException, XMLSecurityException {
+        if (signaturePartDef.getTransformAlgo() != null) {
+            List<XMLSecAttribute> attributes = new ArrayList<XMLSecAttribute>(1);
+            attributes.add(createAttribute(XMLSecurityConstants.ATT_NULL_Algorithm, signaturePartDef.getTransformAlgo()));
+            createStartElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform, false, attributes);
+            createEndElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform);
+        } else {
+            List<XMLSecAttribute> attributes = new ArrayList<XMLSecAttribute>(1);
+            attributes.add(createAttribute(XMLSecurityConstants.ATT_NULL_Algorithm, signaturePartDef.getC14nAlgo()));
+            createStartElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform, false, attributes);
+            createEndElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform);
+        }
+    }
+    
+    private static void flushBufferAndCallbackAfterTokenID(OutputProcessorChain outputProcessorChain,
+            AbstractBufferingOutputProcessor abstractBufferingOutputProcessor,
+            Deque<XMLSecEvent> xmlSecEventDeque
+    ) throws XMLStreamException, XMLSecurityException {
+        final Iterator<XMLSecEvent> xmlSecEventIterator = xmlSecEventDeque.descendingIterator();
+
+        String appendAfterThisTokenId = abstractBufferingOutputProcessor.getAppendAfterThisTokenId();
+
+        //append current header
+        if (appendAfterThisTokenId == null) {
+            abstractBufferingOutputProcessor.processHeaderEvent(outputProcessorChain);
+        } else {
+            //we have a dependent token. so we have to append the current header after the token
+            QName matchingElementName = null;
+
+            loop:
+            while (xmlSecEventIterator.hasNext()) {
+                XMLSecEvent xmlSecEvent = xmlSecEventIterator.next();
+
+                outputProcessorChain.reset();
+                outputProcessorChain.processEvent(xmlSecEvent);
+                switch (xmlSecEvent.getEventType()) {
+                    //search for an element with a matching wsu:Id. this is our token
+                    case XMLStreamConstants.START_ELEMENT:
+                        XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
+                        List<XMLSecAttribute> xmlSecAttributes = xmlSecStartElement.getOnElementDeclaredAttributes();
+                        for (int i = 0; i < xmlSecAttributes.size(); i++) {
+                            XMLSecAttribute xmlSecAttribute = xmlSecAttributes.get(i);
+                            final QName attributeName = xmlSecAttribute.getName();
+                            final String attributeValue = xmlSecAttribute.getValue();
+                            if (XMLSecurityConstants.ATT_NULL_Id.equals(attributeName)
+                                    && appendAfterThisTokenId.equals(attributeValue)) {
+                                matchingElementName = xmlSecStartElement.getName();
+                                break loop;
+                            }
+                        }
+                        break;
+                }
+            }
+
+            //we found the token and...
+            int level = 0;
+            loop:
+            while (xmlSecEventIterator.hasNext()) {
+                XMLSecEvent xmlSecEvent = xmlSecEventIterator.next();
+
+                outputProcessorChain.reset();
+                outputProcessorChain.processEvent(xmlSecEvent);
+                //...loop until we reach the token end element
+                switch (xmlSecEvent.getEventType()) {
+                    case XMLStreamConstants.START_ELEMENT:
+                        level++;
+                        break;
+                    case XMLStreamConstants.END_ELEMENT:
+                        XMLSecEndElement xmlSecEndElement = xmlSecEvent.asEndElement();
+                        if (level == 0 && xmlSecEndElement.getName().equals(matchingElementName)) {
+                            //output now the current header
+                            abstractBufferingOutputProcessor.processHeaderEvent(outputProcessorChain);
+                            break loop;
+                        }
+                        level--;
+                        break;
+                }
+            }
+        }
+        
+        //loop through the rest of the document
+        while (xmlSecEventIterator.hasNext()) {
+            XMLSecEvent xmlSecEvent = xmlSecEventIterator.next();
+            outputProcessorChain.reset();
+            outputProcessorChain.processEvent(xmlSecEvent);
+        }
+        outputProcessorChain.reset();
+    }
+}

Added: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureOutputProcessor.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureOutputProcessor.java?rev=1355316&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureOutputProcessor.java (added)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureOutputProcessor.java Fri Jun 29 11:16:19 2012
@@ -0,0 +1,125 @@
+/**
+ * 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.xml.security.stax.impl.processor.output;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.xml.security.stax.ext.OutputProcessorChain;
+import org.apache.xml.security.stax.ext.SecurePart;
+import org.apache.xml.security.stax.ext.XMLSecurityConstants;
+import org.apache.xml.security.stax.ext.XMLSecurityException;
+import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
+import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
+import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
+import org.apache.xml.security.stax.impl.SignaturePartDef;
+import org.apache.xml.security.stax.impl.util.IDGenerator;
+
+/**
+ * An OutputProcessor for XML Signature.
+ */
+public class XMLSignatureOutputProcessor extends AbstractSignatureOutputProcessor {
+    
+    private static final transient Log logger = LogFactory.getLog(XMLSignatureOutputProcessor.class);
+
+    public XMLSignatureOutputProcessor() throws XMLSecurityException {
+        super();
+    }
+    
+    @Override
+    public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
+        super.init(outputProcessorChain);
+        XMLSignatureEndingOutputProcessor signatureEndingOutputProcessor = new XMLSignatureEndingOutputProcessor(this);
+        signatureEndingOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
+        signatureEndingOutputProcessor.setAction(getAction());
+        signatureEndingOutputProcessor.init(outputProcessorChain);
+    }
+
+    @Override
+    public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain) throws XMLStreamException, XMLSecurityException {
+        if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
+            XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
+
+            //avoid double signature when child elements matches too
+            if (getActiveInternalSignatureOutputProcessor() == null) {
+                SecurePart securePart = securePartMatches(xmlSecStartElement, outputProcessorChain, XMLSecurityConstants.SIGNATURE_PARTS);
+                if (securePart != null) {
+                    logger.debug("Matched securePart for signature");
+
+                    InternalSignatureOutputProcessor internalSignatureOutputProcessor = null;
+                    try {
+                        SignaturePartDef signaturePartDef = new SignaturePartDef();
+                        if (securePart.getIdToSign() == null) {
+                            signaturePartDef.setSigRefId(IDGenerator.generateID(null));
+                            signaturePartDef.setC14nAlgo(getSecurityProperties().getSignatureCanonicalizationAlgorithm());
+
+                            Attribute attribute = xmlSecStartElement.getAttributeByName(XMLSecurityConstants.ATT_NULL_Id);
+                            if (attribute != null) {
+                                signaturePartDef.setSigRefId(attribute.getValue());
+                            } else {
+                                List<XMLSecAttribute> attributeList = new ArrayList<XMLSecAttribute>(1);
+                                attributeList.add(createAttribute(XMLSecurityConstants.ATT_NULL_Id, signaturePartDef.getSigRefId()));
+                                xmlSecEvent = addAttributes(xmlSecStartElement, attributeList);
+                            }
+                            outputProcessorChain.getSecurityContext().put(
+                                XMLSecurityConstants.PROP_APPEND_SIGNATURE_ON_THIS_ID, 
+                                signaturePartDef.getSigRefId()
+                            );
+                        } else {
+                            signaturePartDef.setSigRefId(securePart.getIdToSign());
+                            signaturePartDef.setC14nAlgo(getSecurityProperties().getSignatureCanonicalizationAlgorithm());
+                            outputProcessorChain.getSecurityContext().put(
+                                    XMLSecurityConstants.PROP_APPEND_SIGNATURE_ON_THIS_ID, 
+                                    securePart.getIdToSign()
+                            );
+                        }
+
+                        getSignaturePartDefList().add(signaturePartDef);
+                        internalSignatureOutputProcessor = new InternalSignatureOutputProcessor(signaturePartDef, xmlSecStartElement.getName());
+                        internalSignatureOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
+                        internalSignatureOutputProcessor.setAction(getAction());
+                        internalSignatureOutputProcessor.addAfterProcessor(XMLSignatureOutputProcessor.class.getName());
+                        internalSignatureOutputProcessor.addBeforeProcessor(XMLSignatureEndingOutputProcessor.class.getName());
+                        internalSignatureOutputProcessor.init(outputProcessorChain);
+
+                    } catch (NoSuchAlgorithmException e) {
+                        throw new XMLSecurityException(
+                                XMLSecurityException.ErrorCode.UNSUPPORTED_ALGORITHM, "unsupportedKeyTransp",
+                                e, "No such algorithm: " + getSecurityProperties().getSignatureAlgorithm()
+                        );
+                    } catch (NoSuchProviderException e) {
+                        throw new XMLSecurityException(XMLSecurityException.ErrorCode.FAILURE, "noSecProvider", e);
+                    }
+
+                    setActiveInternalSignatureOutputProcessor(internalSignatureOutputProcessor);
+                }
+            }
+        }
+        outputProcessorChain.processEvent(xmlSecEvent);
+    }
+
+}

Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/DSNamespaceContext.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/DSNamespaceContext.java?rev=1355316&r1=1355315&r2=1355316&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/DSNamespaceContext.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/dom/DSNamespaceContext.java Fri Jun 29 11:16:19 2012
@@ -34,6 +34,7 @@ public class DSNamespaceContext implemen
     
     public DSNamespaceContext() {
         namespaceMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
+        namespaceMap.put("dsig", "http://www.w3.org/2000/09/xmldsig#");
     }
     
     public DSNamespaceContext(Map<String, String> namespaces) {

Added: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/SignatureTest.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/SignatureTest.java?rev=1355316&view=auto
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/SignatureTest.java (added)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/stax/signature/SignatureTest.java Fri Jun 29 11:16:19 2012
@@ -0,0 +1,311 @@
+/**
+ * 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.xml.security.test.stax.signature;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.security.Key;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import java.util.UUID;
+
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.XMLStreamWriter;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+
+import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.signature.XMLSignature;
+import org.apache.xml.security.stax.config.Init;
+import org.apache.xml.security.stax.crypto.CryptoType;
+import org.apache.xml.security.stax.ext.SecurePart;
+import org.apache.xml.security.stax.ext.SecurityToken;
+import org.apache.xml.security.stax.ext.SecurityTokenProvider;
+import org.apache.xml.security.stax.ext.XMLSecurityConstants;
+import org.apache.xml.security.stax.ext.XMLSecurityException;
+import org.apache.xml.security.stax.ext.XMLSecurityProperties;
+import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
+import org.apache.xml.security.stax.impl.DocumentContextImpl;
+import org.apache.xml.security.stax.impl.OutputProcessorChainImpl;
+import org.apache.xml.security.stax.impl.SecurityContextImpl;
+import org.apache.xml.security.stax.impl.XMLSecurityStreamWriter;
+import org.apache.xml.security.stax.impl.processor.output.FinalOutputProcessor;
+import org.apache.xml.security.stax.impl.processor.output.XMLSignatureOutputProcessor;
+import org.apache.xml.security.test.dom.DSNamespaceContext;
+import org.apache.xml.security.test.stax.utils.XMLSecEventAllocator;
+import org.apache.xml.security.test.stax.utils.XmlReaderToWriter;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ * A set of test-cases for Signature creation.
+ */
+public class SignatureTest extends org.junit.Assert {
+
+    private XMLInputFactory xmlInputFactory;
+    private DocumentBuilderFactory documentBuilderFactory;
+    
+    static {
+        try {
+            Class<?> c =
+                    SignatureTest.class.getClassLoader().loadClass(
+                            "org.bouncycastle.jce.provider.BouncyCastleProvider"
+                    );
+            if (null == Security.getProvider("BC")) {
+                // Security.addProvider((Provider) c.newInstance());
+                Security.insertProviderAt((Provider) c.newInstance(), 1);
+            }
+        } catch (Throwable e) {
+            throw new RuntimeException("Adding BouncyCastle provider failed", e);
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Init.init(SignatureTest.class.getClassLoader().getResource("security-config.xml").toURI());
+        org.apache.xml.security.Init.init();
+        
+        xmlInputFactory = XMLInputFactory.newInstance();
+        xmlInputFactory.setEventAllocator(new XMLSecEventAllocator());
+        
+        documentBuilderFactory = DocumentBuilderFactory.newInstance();
+        documentBuilderFactory.setNamespaceAware(true);
+        documentBuilderFactory.setIgnoringComments(false);
+        documentBuilderFactory.setCoalescing(false);
+        documentBuilderFactory.setIgnoringElementContentWhitespace(false);
+    }
+
+    @Test
+    public void testSignatureCreation() throws Exception {
+        // Set up the Configuration
+        XMLSecurityProperties properties = new XMLSecurityProperties();
+        XMLSecurityConstants.Action[] actions = 
+            new XMLSecurityConstants.Action[]{XMLSecurityConstants.SIGNATURE};
+        properties.setOutAction(actions);
+        properties.loadSignatureKeyStore(
+            this.getClass().getClassLoader().getResource("transmitter.jks"), "default".toCharArray()
+        );
+        properties.setSignatureUser("transmitter");
+        properties.setSignatureAlgorithm("http://www.w3.org/2000/09/xmldsig#rsa-sha1");
+        properties.setSignatureCanonicalizationAlgorithm("http://www.w3.org/2001/10/xml-exc-c14n#");
+        properties.setSignatureDigestAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1");
+        
+        SecurePart securePart = 
+               new SecurePart(new QName("urn:example:po", "PaymentInfo"), SecurePart.Modifier.Content);
+        properties.addSignaturePart(securePart);
+        
+        // Set the key up
+        SecurityContextImpl securityContextImpl = new SecurityContextImpl();
+        Key key = properties.getSignatureCrypto().getPrivateKey("transmitter", "default");
+        CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
+        cryptoType.setAlias(properties.getSignatureUser());
+        X509Certificate[] x509Certificates = properties.getSignatureCrypto().getX509Certificates(cryptoType);
+        
+        SignatureSecurityToken securityToken = new SignatureSecurityToken(key, x509Certificates);
+        String id = UUID.randomUUID().toString();
+        SignatureSecurityTokenProvider securityTokenProvider = 
+                new SignatureSecurityTokenProvider(securityToken, id);
+        securityContextImpl.registerSecurityTokenProvider(id, securityTokenProvider);
+        securityContextImpl.put(XMLSecurityConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, id);
+        securityContextImpl.putAsMap(XMLSecurityConstants.SIGNATURE_PARTS, securePart.getName(), securePart);
+
+        final DocumentContextImpl documentContext = new DocumentContextImpl();
+        documentContext.setEncoding("UTF-8");
+        InputStream sourceDocument = 
+                this.getClass().getClassLoader().getResourceAsStream(
+                        "ie/baltimore/merlin-examples/merlin-xmlenc-five/plaintext.xml");
+        
+        OutputProcessorChainImpl processorChain = 
+            new OutputProcessorChainImpl(securityContextImpl, documentContext);
+        XMLSignatureOutputProcessor signatureOutputProcessor = new XMLSignatureOutputProcessor();
+        signatureOutputProcessor.setXMLSecurityProperties(properties);
+        signatureOutputProcessor.setAction(XMLSecurityConstants.SIGNATURE);
+        signatureOutputProcessor.init(processorChain);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        FinalOutputProcessor finalOutputProcessor = new FinalOutputProcessor(baos, "UTF-8");
+        finalOutputProcessor.setXMLSecurityProperties(properties);
+        finalOutputProcessor.setAction(null);
+        finalOutputProcessor.init(processorChain);
+        processorChain.addProcessor(finalOutputProcessor);
+        
+        XMLStreamWriter xmlStreamWriter = new XMLSecurityStreamWriter(processorChain);
+        
+        XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(sourceDocument);
+        XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
+        xmlStreamWriter.close();
+        
+        // System.out.println("Got:\n" + new String(baos.toByteArray(), "UTF-8"));
+        Document document = 
+            documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
+        
+        // Verify using DOM
+        verifyUsingDOM(document, x509Certificates[0], securePart);
+    }
+
+    /**
+     * Verify the document using DOM
+     */
+    private void verifyUsingDOM(
+        Document document,
+        X509Certificate cert,
+        SecurePart securePart
+    ) throws Exception {
+        XPathFactory xpf = XPathFactory.newInstance();
+        XPath xpath = xpf.newXPath();
+        xpath.setNamespaceContext(new DSNamespaceContext());
+
+        String expression = "//dsig:Signature[1]";
+        Element sigElement = 
+            (Element) xpath.evaluate(expression, document, XPathConstants.NODE);
+        Assert.assertNotNull(sigElement);
+        
+        expression = "//*[local-name()='" + securePart.getName().getLocalPart() + "']";
+        Element signedElement = 
+            (Element)xpath.evaluate(expression, document, XPathConstants.NODE);
+        Assert.assertNotNull(signedElement);
+        signedElement.setIdAttributeNS(null, "Id", true);
+        
+        XMLSignature signature = new XMLSignature(sigElement, "");
+        KeyInfo ki = signature.getKeyInfo();
+        Assert.assertNotNull(ki);
+
+        Assert.assertTrue(signature.checkSignatureValue(cert));
+    }
+    
+    private static class SignatureSecurityToken implements SecurityToken {
+        private Key key;
+        private X509Certificate[] certs;
+        
+        public SignatureSecurityToken(Key key, X509Certificate[] certs) {
+            this.key = key;
+            this.certs = certs;
+        }
+
+        public String getId() {
+            return null;
+        }
+
+
+        public Object getProcessor() {
+            return null;
+        }
+
+        public boolean isAsymmetric() {
+            return false;
+        }
+
+        public Key getSecretKey(
+            String algorithmURI, XMLSecurityConstants.KeyUsage keyUsage
+        ) throws XMLSecurityException {
+            return key;
+        }
+
+        public PublicKey getPublicKey(
+            String algorithmURI, XMLSecurityConstants.KeyUsage keyUsage
+        ) throws XMLSecurityException {
+            return null;
+        }
+
+        public X509Certificate[] getX509Certificates() throws XMLSecurityException {
+            return certs;
+        }
+
+        public void verify() throws XMLSecurityException {
+        }
+
+        public SecurityToken getKeyWrappingToken() {
+            return null;
+        }
+
+        public XMLSecurityConstants.TokenType getTokenType() {
+            return null;
+        }
+
+        @Override
+        public List<QName> getElementPath() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public XMLSecEvent getXMLSecEvent() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public List<SecurityToken> getWrappedTokens()
+                throws XMLSecurityException {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        @Override
+        public void addWrappedToken(SecurityToken securityToken) {
+            // TODO Auto-generated method stub
+            
+        }
+
+        @Override
+        public void addTokenUsage(TokenUsage tokenUsage)
+                throws XMLSecurityException {
+            // TODO Auto-generated method stub
+            
+        }
+
+        @Override
+        public List<TokenUsage> getTokenUsages() {
+            // TODO Auto-generated method stub
+            return null;
+        }
+    };
+
+    private static class SignatureSecurityTokenProvider implements SecurityTokenProvider {
+        private SecurityToken token;
+        private String id;
+        
+        public SignatureSecurityTokenProvider(SecurityToken token, String id) {
+            this.token = token;
+        }
+        
+        @Override
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public SecurityToken getSecurityToken() throws XMLSecurityException {
+            return token;
+        }
+    };
+
+
+}
\ No newline at end of file