First cut at signing support.
authorScott Cantor <cantor.2@osu.edu>
Sun, 12 Mar 2006 00:00:30 +0000 (00:00 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 12 Mar 2006 00:00:30 +0000 (00:00 +0000)
32 files changed:
.cdtproject
xmltooling/AbstractDOMCachingXMLObject.cpp
xmltooling/AbstractDOMCachingXMLObject.h
xmltooling/Makefile.am
xmltooling/XMLObject.h
xmltooling/XMLObjectBuilder.h
xmltooling/XMLToolingConfig.cpp
xmltooling/exceptions.h
xmltooling/impl/UnknownElement.cpp
xmltooling/impl/UnknownElement.h
xmltooling/internal.h
xmltooling/io/AbstractXMLObjectMarshaller.cpp
xmltooling/io/AbstractXMLObjectMarshaller.h
xmltooling/io/AbstractXMLObjectUnmarshaller.cpp
xmltooling/io/AbstractXMLObjectUnmarshaller.h
xmltooling/io/Marshaller.h
xmltooling/signature/KeyInfo.h [new file with mode: 0644]
xmltooling/signature/Signature.h [new file with mode: 0644]
xmltooling/signature/SigningContext.h [new file with mode: 0644]
xmltooling/signature/impl/XMLSecSignature.cpp [new file with mode: 0644]
xmltooling/signature/impl/XMLSecSignature.h [new file with mode: 0644]
xmltooling/util/ParserPool.cpp
xmltooling/util/XMLHelper.h
xmltooling/util/XMLObjectChildrenList.h
xmltooling/xmltooling.vcproj
xmltoolingtest/ComplexXMLObjectTest.h
xmltoolingtest/Makefile.am
xmltoolingtest/SignatureTest.h [new file with mode: 0644]
xmltoolingtest/XMLObjectBaseTestCase.h
xmltoolingtest/data/cert.pem [new file with mode: 0644]
xmltoolingtest/data/key.pem [new file with mode: 0644]
xmltoolingtest/xmltoolingtest.vcproj

index 3db5ea8..3d9715b 100644 (file)
 <pathentry kind="mac" name="WIN32" path="" value=""/>\r
 <pathentry kind="out" path=""/>\r
 <pathentry kind="con" path="org.eclipse.cdt.make.core.DISCOVERED_SCANNER_INFO"/>\r
-<pathentry excluding="util/|io/|impl/|validation/" kind="src" path="xmltooling"/>\r
+<pathentry excluding="util/|io/|impl/|validation/|signature/|signature/impl/" kind="src" path="xmltooling"/>\r
 <pathentry kind="src" path="xmltooling/util"/>\r
 <pathentry kind="src" path="xmltooling/io"/>\r
 <pathentry kind="src" path="xmltooling/impl"/>\r
 <pathentry kind="src" path="xmltoolingtest"/>\r
 <pathentry kind="src" path="xmltooling/validation"/>\r
+<pathentry excluding="impl/" kind="src" path="xmltooling/signature"/>\r
+<pathentry kind="src" path="xmltooling/signature/impl"/>\r
 </item>\r
 </data>\r
 </cdtproject>\r
index 655f22d..7ffc58c 100644 (file)
@@ -123,6 +123,8 @@ XMLObject* AbstractDOMCachingXMLObject::clone() const
             Category::getInstance(XMLTOOLING_LOGCAT".DOM").error(\r
                 "DOM clone failed, unable to locate unmarshaller for element (%s)", q->toString().c_str()\r
                 );\r
+            domCopy->getOwnerDocument()->release();\r
+            throw UnmarshallingException("Unable to locate unmarshaller for cloned element.");\r
         }\r
         try {\r
             return u->unmarshall(domCopy, true);    // bind document\r
@@ -133,3 +135,28 @@ XMLObject* AbstractDOMCachingXMLObject::clone() const
     }\r
     return NULL;\r
 }\r
+\r
+XMLObject* AbstractDOMCachingXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObject* newValue) {\r
+\r
+    if (newValue && newValue->hasParent())\r
+        throw XMLObjectException("child XMLObject cannot be added - it is already the child of another XMLObject");\r
+\r
+    if (!oldValue) {\r
+        if (newValue) {\r
+            releaseThisandParentDOM();\r
+            newValue->setParent(this);\r
+            return newValue;\r
+        }\r
+        else {\r
+            return NULL;\r
+        }\r
+    }\r
+\r
+    if (oldValue != newValue) {\r
+        delete oldValue;\r
+        releaseThisandParentDOM();\r
+        newValue->setParent(this);\r
+    }\r
+\r
+    return newValue;\r
+}\r
index ce8d2c4..501f039 100644 (file)
@@ -124,24 +124,41 @@ namespace xmltooling {
 \r
         /**\r
          * A helper function for derived classes.\r
-         * This 'normalizes' newString and then if it is different from oldString\r
-         * invalidates the DOM. It returns the normalized value.\r
+         * This 'normalizes' newString, and then if it is different from oldString,\r
+         * it invalidates the DOM, frees the old string, and return the new.\r
+         * If not different, it frees the new string and just returns the old value.\r
          * \r
          * @param oldValue - the current value\r
          * @param newValue - the new value\r
          * \r
          * @return the value that should be assigned\r
          */\r
-        XMLCh* prepareForAssignment(const XMLCh* oldValue, const XMLCh* newValue) {\r
+        XMLCh* prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue) {\r
             XMLCh* newString = XMLString::replicate(newValue);\r
             XMLString::trim(newString);\r
-\r
-            if (!XMLString::equals(oldValue,newValue))\r
+            if (!XMLString::equals(oldValue,newValue)) {\r
                 releaseThisandParentDOM();\r
-    \r
-            return newString;\r
+                XMLString::release(&oldValue);\r
+                return newString;\r
+            }\r
+            XMLString::release(&newString);\r
+            return oldValue;            \r
         }\r
-    \r
+\r
+        /**\r
+         * A helper function for derived classes, for assignment of (singleton) XML objects.\r
+         * \r
+         * It is indifferent to whether either the old or the new version of the value is null. \r
+         * This method will do a safe compare of the objects and will also invalidate the DOM if appropriate\r
+         * \r
+         * @param oldValue - current value\r
+         * @param newValue - proposed new value\r
+         * @return the value to assign \r
+         * \r
+         * @throws XMLObjectException if the new child already has a parent.\r
+         */\r
+        XMLObject* prepareForAssignment(XMLObject* oldValue, XMLObject* newValue);\r
+\r
     private:\r
         DOMElement* m_dom;\r
         DOMDocument* m_document;\r
index 4749b15..2796597 100644 (file)
@@ -6,6 +6,8 @@ libxmltoolingincludedir = $(includedir)/xmltooling
 
 ioincludedir = $(includedir)/xmltooling/io
 
+sigincludedir = $(includedir)/xmltooling/signature
+
 utilincludedir = $(includedir)/xmltooling/util
 
 valincludedir = $(includedir)/xmltooling/validation
@@ -35,6 +37,11 @@ ioinclude_HEADERS = \
     io/Marshaller.h \
     io/Unmarshaller.h
 
+siginclude_HEADERS = \
+    signature/KeyInfo.h \
+    signature/Signature.h \
+    signature/SigningContext.h
+
 utilinclude_HEADERS = \
     util/NDC.h \
     util/ParserPool.h \
@@ -47,7 +54,8 @@ valinclude_HEADERS = \
 
 noinst_HEADERS = \
     internal.h \
-    impl/UnknownElement.h
+    impl/UnknownElement.h \
+    signature/impl/XMLSecSignature.h
 
 libxmltooling_la_SOURCES = \
     AbstractAttributeExtensibleXMLObject.cpp \
@@ -63,6 +71,7 @@ libxmltooling_la_SOURCES = \
     io/AbstractXMLObjectUnmarshaller.cpp \
     io/Marshaller.cpp \
     io/Unmarshaller.cpp \
+    signature/impl/XMLSecSignature.cpp \
     util/NDC.cpp \
     util/ParserPool.cpp \
     util/XMLConstants.cpp \
index e8fb52a..1ff2ce7 100644 (file)
@@ -37,7 +37,6 @@ namespace xmltooling {
     {\r
         MAKE_NONCOPYABLE(XMLObject);\r
     public:\r
-        XMLObject() {}\r
         virtual ~XMLObject() {}\r
         \r
         /**\r
@@ -143,6 +142,9 @@ namespace xmltooling {
          * @return the list of children\r
          */\r
         virtual const std::list<XMLObject*>& getOrderedChildren() const=0;\r
+\r
+    protected:\r
+        XMLObject() {}\r
     };\r
 \r
 };\r
index a4c4311..de34c89 100644 (file)
@@ -55,6 +55,17 @@ namespace xmltooling {
         virtual XMLObject* buildObject() const=0;\r
 \r
         /**\r
+         * Creates an empty XMLObject using the default build method, if a builder can be found.\r
+         * \r
+         * @param key   the key used to locate a builder\r
+         * @return  the empty object or NULL if no builder is available \r
+         */\r
+        static XMLObject* buildObject(const QName& key) {\r
+            const XMLObjectBuilder* b=getBuilder(key);\r
+            return b ? b->buildObject() : NULL;\r
+        }\r
+\r
+        /**\r
          * Retrieves an XMLObjectBuilder using the key it was registered with.\r
          * \r
          * @param key the key used to register the builder\r
index 3f15fac..8170abf 100644 (file)
@@ -23,6 +23,7 @@
 #include "internal.h"\r
 #include "XMLToolingConfig.h"\r
 #include "impl/UnknownElement.h"\r
+#include "signature/impl/XMLSecSignature.h"\r
 #include "util/NDC.h"\r
 \r
 #ifdef HAVE_DLFCN_H\r
@@ -33,7 +34,9 @@
 #include <log4cpp/PropertyConfigurator.hh>\r
 #include <log4cpp/OstreamAppender.hh>\r
 #include <xercesc/util/PlatformUtils.hpp>\r
-#include <xsec/framework/XSECProvider.hpp>\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    #include <xsec/framework/XSECProvider.hpp>\r
+#endif\r
 \r
 #include <stdexcept>\r
 \r
@@ -126,10 +129,12 @@ bool XMLToolingInternalConfig::init()
         xercesc::XMLPlatformUtils::Initialize();\r
         log.debug("Xerces initialization complete");\r
 \r
+#ifndef XMLTOOLING_NO_XMLSEC\r
         XSECPlatformUtils::Initialise();\r
-        //m_xsec=new XSECProvider();\r
+        m_xsecProvider=new XSECProvider();\r
         log.debug("XMLSec initialization complete");\r
-        \r
+#endif\r
+\r
         m_parserPool=new ParserPool();\r
         m_lock=xercesc::XMLPlatformUtils::makeMutex();\r
 \r
@@ -137,6 +142,11 @@ bool XMLToolingInternalConfig::init()
         XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());\r
         Marshaller::registerDefaultMarshaller(new UnknownElementMarshaller());\r
         Unmarshaller::registerDefaultUnmarshaller(new UnknownElementUnmarshaller());\r
+        \r
+        QName dsig(XMLConstants::XMLSIG_NS,Signature::LOCAL_NAME);\r
+        XMLObjectBuilder::registerBuilder(dsig,new XMLSecSignatureBuilder());\r
+        Marshaller::registerMarshaller(dsig,new XMLSecSignatureMarshaller());\r
+        Unmarshaller::registerUnmarshaller(dsig,new XMLSecSignatureUnmarshaller());\r
     }\r
     catch (const xercesc::XMLException&) {\r
         log.fatal("caught exception while initializing Xerces");\r
@@ -149,10 +159,9 @@ bool XMLToolingInternalConfig::init()
 \r
 void XMLToolingInternalConfig::term()\r
 {\r
-    // default registrations\r
-    XMLObjectBuilder::deregisterDefaultBuilder();\r
-    Marshaller::deregisterDefaultMarshaller();\r
-    Unmarshaller::deregisterDefaultUnmarshaller();\r
+    XMLObjectBuilder::destroyBuilders();\r
+    Marshaller::destroyMarshallers();\r
+    Unmarshaller::destroyUnmarshallers();\r
 \r
     for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {\r
 #if defined(WIN32)\r
@@ -174,8 +183,12 @@ void XMLToolingInternalConfig::term()
     delete m_parserPool;\r
     m_parserPool=NULL;\r
 \r
-    //delete m_xsec; m_xsec=NULL;\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    delete m_xsecProvider;\r
+    m_xsecProvider=NULL;\r
     XSECPlatformUtils::Terminate();\r
+#endif\r
+\r
     xercesc::XMLPlatformUtils::closeMutex(m_lock);\r
     m_lock=NULL;\r
     xercesc::XMLPlatformUtils::Terminate();\r
index 84f47be..f527350 100644 (file)
@@ -60,6 +60,7 @@ namespace xmltooling {
     DECL_XMLTOOLING_EXCEPTION(UnknownElementException);\r
     DECL_XMLTOOLING_EXCEPTION(UnknownAttributeException);\r
     DECL_XMLTOOLING_EXCEPTION(ValidationException);\r
+    DECL_XMLTOOLING_EXCEPTION(SignatureException);\r
 \r
 };\r
 \r
index 745abe9..3d638ae 100644 (file)
@@ -70,7 +70,7 @@ void UnknownElementImpl::serialize(string& s) const
         XMLHelper::serialize(getDOM(),s);\r
 }\r
 \r
-DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const\r
+DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document, MarshallingContext* ctx) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -93,13 +93,19 @@ DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument
             return cachedDOM;\r
         }\r
         \r
-        // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
-        // Without an adoptNode option to maintain the child pointers, we rely on our custom\r
-        // implementation class to preserve the XML when we release the existing DOM.\r
-        unk->releaseDOM();\r
+        // We have a DOM but it doesn't match the document we were given, so we import\r
+        // it into the new document.\r
+        cachedDOM=static_cast<DOMElement*>(document->importNode(cachedDOM, true));\r
+\r
+        // Recache the DOM.\r
+        setDocumentElement(document, cachedDOM);\r
+        log.debug("caching imported DOM for XMLObject");\r
+        unk->setDOM(cachedDOM, false);\r
+        unk->releaseParentDOM(true);\r
+        return cachedDOM;\r
     }\r
     \r
-    // If we get here, we didn't have a usable DOM (and/or we flushed the one we had).\r
+    // If we get here, we didn't have a usable DOM.\r
     // We need to reparse the XML we saved off into a new DOM.\r
     bool bindDocument=false;\r
     MemBufInputSource src(reinterpret_cast<const XMLByte*>(unk->m_xml.c_str()),unk->m_xml.length(),"UnknownElementImpl");\r
@@ -129,7 +135,7 @@ DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMDocument
     return cachedDOM;\r
 }\r
 \r
-DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement) const\r
+DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -151,10 +157,16 @@ DOMElement* UnknownElementMarshaller::marshall(XMLObject* xmlObject, DOMElement*
             return cachedDOM;\r
         }\r
         \r
-        // We have a DOM but it doesn't match the document we were given. This both sucks and blows.\r
-        // Without an adoptNode option to maintain the child pointers, we rely on our custom\r
-        // implementation class to preserve the XML when we release the existing DOM.\r
-        unk->releaseDOM();\r
+        // We have a DOM but it doesn't match the document we were given, so we import\r
+        // it into the new document.\r
+        cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(cachedDOM, true));\r
+\r
+        // Recache the DOM.\r
+        parentElement->appendChild(cachedDOM);\r
+        log.debug("caching imported DOM for XMLObject");\r
+        unk->setDOM(cachedDOM, false);\r
+        unk->releaseParentDOM(true);\r
+        return cachedDOM;\r
     }\r
     \r
     // If we get here, we didn't have a usable DOM (and/or we flushed the one we had).\r
index aff3ae5..1afb6e1 100644 (file)
@@ -46,6 +46,9 @@ namespace xmltooling {
     class XMLTOOL_DLLLOCAL UnknownElementImpl : public AbstractDOMCachingXMLObject\r
     {\r
     public:\r
+        UnknownElementImpl(const XMLCh* namespaceURI=NULL, const XMLCh* elementLocalName=NULL, const XMLCh* namespacePrefix=NULL)\r
+            : AbstractDOMCachingXMLObject(namespaceURI, elementLocalName, namespacePrefix) {}\r
+    \r
         /**\r
          * Overridden to ensure XML content of DOM isn't lost.\r
          * \r
@@ -64,9 +67,9 @@ namespace xmltooling {
          */\r
         std::string m_xml;\r
 \r
-    private:\r
         void serialize(std::string& s) const;\r
-        friend class XMLTOOL_API UnknownElementMarshaller;\r
+    private:\r
+        friend class XMLTOOL_DLLLOCAL UnknownElementMarshaller;\r
     };\r
 \r
     /**\r
@@ -90,14 +93,14 @@ namespace xmltooling {
     {\r
     public:\r
         /**\r
-         * @see Marshaller::marshall(XMLObject*,DOMDocument*)\r
+         * @see Marshaller::marshall(XMLObject*,DOMDocument*, const MarshallingContext*)\r
          */\r
-        DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL) const;\r
+        DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const;\r
 \r
         /**\r
-         * @see Marshaller::marshall(XMLObject*,DOMElement*)\r
+         * @see Marshaller::marshall(XMLObject*,DOMElement*, const MarshallingContext* ctx)\r
          */\r
-        DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement) const;\r
+        DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx=NULL) const;\r
         \r
     protected:\r
         void setDocumentElement(DOMDocument* document, DOMElement* element) const {\r
@@ -110,7 +113,7 @@ namespace xmltooling {
     };\r
 \r
     /**\r
-     * Marshaller for UnknownElementImpl objects\r
+     * Unmarshaller for UnknownElementImpl objects\r
      */\r
     class XMLTOOL_DLLLOCAL UnknownElementUnmarshaller : public virtual Unmarshaller\r
     {\r
index 2d7c6fa..42548e0 100644 (file)
@@ -38,6 +38,9 @@
 #include "util/ParserPool.h"\r
 \r
 #include <vector>\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    #include <xsec/framework/XSECProvider.hpp>\r
+#endif\r
 \r
 #define XMLTOOLING_LOGCAT "XMLTooling"\r
 \r
@@ -46,7 +49,7 @@ namespace xmltooling {
     class XMLToolingInternalConfig : public xmltooling::XMLToolingConfig\r
     {\r
     public:\r
-        XMLToolingInternalConfig() : m_lock(NULL), m_parserPool(NULL) {}\r
+        XMLToolingInternalConfig() : m_lock(NULL), m_parserPool(NULL), m_xsecProvider(NULL) {}\r
 \r
         static XMLToolingInternalConfig& getInternalConfig();\r
 \r
@@ -64,11 +67,11 @@ namespace xmltooling {
 \r
         // internal parser pool\r
         xmltooling::ParserPool* m_parserPool;\r
+        XSECProvider* m_xsecProvider;\r
 \r
     private:\r
         std::vector<void*> m_libhandles;\r
         void* m_lock;\r
-        //XSECProvider* m_xsec;\r
         //PlugManager m_plugMgr;\r
     };\r
 };\r
index d5c4ac0..8a718a7 100644 (file)
@@ -42,7 +42,7 @@ using namespace std;
 AbstractXMLObjectMarshaller::AbstractXMLObjectMarshaller()\r
     : m_log(&Category::getInstance(XMLTOOLING_LOGCAT".Marshaller")) {}\r
 \r
-DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document) const\r
+DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document, MarshallingContext* ctx) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -88,7 +88,7 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocum
             xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
             );\r
         setDocumentElement(document, domElement);\r
-        marshallInto(*xmlObject, domElement);\r
+        marshallInto(*xmlObject, domElement, ctx);\r
 \r
         //Recache the DOM.\r
         if (dc) {\r
@@ -108,7 +108,7 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMDocum
     }\r
 }\r
 \r
-DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement) const\r
+DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx) const\r
 {\r
 #ifdef _DEBUG\r
     xmltooling::NDC ndc("marshall");\r
@@ -147,7 +147,7 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMEleme
         xmlObject->getElementQName().getNamespaceURI(), xmlObject->getElementQName().getLocalPart()\r
         );\r
     parentElement->appendChild(domElement);\r
-    marshallInto(*xmlObject, domElement);\r
+    marshallInto(*xmlObject, domElement, ctx);\r
 \r
     //Recache the DOM.\r
     if (dc) {\r
@@ -158,8 +158,19 @@ DOMElement* AbstractXMLObjectMarshaller::marshall(XMLObject* xmlObject, DOMEleme
 \r
     return domElement;\r
 }\r
-        \r
-void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const\r
+\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    class _signit : public unary_function<const pair<Signature*,const SigningContext*>&, void> {\r
+    public:\r
+        void operator()(const pair<Signature*,const SigningContext*>& p) const {\r
+            p.first->sign(p.second);\r
+        }\r
+    };\r
+#endif\r
+\r
+void AbstractXMLObjectMarshaller::marshallInto(\r
+    XMLObject& xmlObject, DOMElement* targetElement, MarshallingContext* ctx\r
+    ) const\r
 {\r
     if (xmlObject.getElementQName().hasPrefix())\r
         targetElement->setPrefix(xmlObject.getElementQName().getPrefix());\r
@@ -169,15 +180,11 @@ void AbstractXMLObjectMarshaller::marshallInto(XMLObject& xmlObject, DOMElement*
     marshallChildElements(xmlObject, targetElement);\r
     marshallElementContent(xmlObject, targetElement);\r
 \r
-    /* TODO Signing/Encryption\r
-    if (xmlObject instanceof SignableXMLObject) {\r
-        signElement(targetElement, xmlObject);\r
-    }\r
-\r
-    if (xmlObject instanceof EncryptableXMLObject) {\r
-        encryptElement(targetElement, xmlObject);\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    if (ctx) {\r
+        for_each(ctx->m_signingContexts.begin(),ctx->m_signingContexts.end(),_signit());\r
     }\r
-    */\r
+#endif\r
 }\r
 \r
 void AbstractXMLObjectMarshaller::marshallElementType(XMLObject& xmlObject, DOMElement* domElement) const\r
@@ -298,7 +305,7 @@ public:
                 );\r
             throw MarshallingException("Marshaller found unknown child element, but no default marshaller was found.");\r
         }\r
-        element->appendChild(marshaller->marshall(obj, element));\r
+        marshaller->marshall(obj, element);\r
     }\r
 };\r
 \r
index beed4b3..7d1928d 100644 (file)
@@ -36,15 +36,14 @@ namespace xmltooling {
         virtual ~AbstractXMLObjectMarshaller() {}\r
 \r
         /**\r
-         * @see Marshaller::marshall(XMLObject*,DOMDocument*)\r
+         * @see Marshaller::marshall(XMLObject*,DOMDocument*,const MarshallingContext*)\r
          */\r
-        DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL) const;\r
+        DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const;\r
 \r
         /**\r
-         * @see Marshaller::marshall(XMLObject*,DOMElement*)\r
+         * @see Marshaller::marshall(XMLObject*,DOMElement*,const MarshallingContext*)\r
          */\r
-        DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement) const;\r
-    \r
+        DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx=NULL) const;\r
         \r
     protected:\r
         AbstractXMLObjectMarshaller();\r
@@ -70,9 +69,12 @@ namespace xmltooling {
          * \r
          * @param xmlObject the XMLObject to marshall\r
          * @param targetElement the Element into which the XMLObject is marshalled into\r
+         * @param ctx           optional marshalling context\r
+         * \r
          * @throws MarshallingException thrown if there is a problem marshalling the object\r
+         * @throws SignatureException thrown if a problem occurs during signature creation \r
          */\r
-        void marshallInto(XMLObject& xmlObject, DOMElement* targetElement) const;\r
+        void marshallInto(XMLObject& xmlObject, DOMElement* targetElement, MarshallingContext* ctx) const;\r
     \r
         /**\r
          * Creates an xsi:type attribute, corresponding to the given type of the XMLObject, on the DOM element.\r
index eeb05fa..e3ae471 100644 (file)
@@ -182,7 +182,7 @@ void AbstractXMLObjectUnmarshaller::unmarshallChildElements(const DOMElement* do
 \r
             // Retain ownership of the unmarshalled child until it's processed by the parent.\r
             auto_ptr<XMLObject> childObject(unmarshaller->unmarshall(static_cast<DOMElement*>(childNode)));\r
-            processChildElement(xmlObject, childObject.get());\r
+            processChildElement(xmlObject, childObject.get(), static_cast<DOMElement*>(childNode));\r
             childObject.release();\r
         }\r
         else if (childNode->getNodeType() == DOMNode::TEXT_NODE) {\r
index 89c8556..f7d05aa 100644 (file)
@@ -86,12 +86,13 @@ namespace xmltooling {
         /**\r
          * Called after a child element has been unmarshalled so that it can be added to the parent XMLObject.\r
          * \r
-         * @param parent the parent XMLObject\r
-         * @param child pointer to the child XMLObject\r
+         * @param parent    the parent XMLObject\r
+         * @param child     pointer to the child XMLObject\r
+         * @param childRoot root element of the child (must not be stored, just a hint)\r
          * \r
          * @throws UnmarshallingException thrown if there is a problem adding the child to the parent\r
          */\r
-        virtual void processChildElement(XMLObject& parent, XMLObject* child) const=0;\r
+        virtual void processChildElement(XMLObject& parent, XMLObject* child, const DOMElement* childRoot) const=0;\r
     \r
         /**\r
          * Called after an attribute has been unmarshalled so that it can be added to the XMLObject.\r
index 0beb061..ba334c4 100644 (file)
 #define __xmltooling_marshaller_h__\r
 \r
 #include <map>\r
+#include <vector>\r
 #include <xercesc/dom/DOM.hpp>\r
 #include <xmltooling/XMLObject.h>\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+    #include <xmltooling/signature/Signature.h>\r
+#endif\r
 \r
 using namespace xercesc;\r
 \r
@@ -37,6 +41,27 @@ using namespace xercesc;
 namespace xmltooling {\r
 \r
     /**\r
+     * Supplies additional information to the marshalling process.\r
+     * Currently this only consists of signature related information.\r
+     */\r
+    class XMLTOOL_API MarshallingContext\r
+    {\r
+        MAKE_NONCOPYABLE(MarshallingContext);\r
+    public:\r
+        MarshallingContext() {}\r
+        ~MarshallingContext() {}\r
+\r
+#ifndef XMLTOOLING_NO_XMLSEC\r
+        MarshallingContext(Signature* sig, const SigningContext* ctx) {\r
+            m_signingContexts.push_back(std::make_pair(sig,ctx));\r
+        }\r
+        \r
+        /** Array of signing contexts, keyed off of the associated Signature */\r
+        std::vector< std::pair<Signature*,const SigningContext*> > m_signingContexts;\r
+#endif\r
+    };\r
+\r
+    /**\r
      * Marshallers are used to marshall an XMLObject into a W3C DOM element.\r
      */\r
     class XMLTOOL_API Marshaller\r
@@ -55,11 +80,14 @@ namespace xmltooling {
          * marshalled, unless an existing DOM can be reused without creating a new document. \r
          * \r
          * @param xmlObject the object to marshall\r
-         * @param document the DOM document the marshalled element will be placed in, or NULL\r
+         * @param document  the DOM document the marshalled element will be placed in, or NULL\r
+         * @param ctx       optional marshalling context\r
          * @return the DOM element representing this XMLObject\r
+         * \r
          * @throws MarshallingException thrown if there is a problem marshalling the given object\r
+         * @throws SignatureException thrown if a problem occurs during signature creation \r
          */\r
-        virtual DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL) const=0;\r
+        virtual DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const=0;\r
         \r
         /**\r
          * Marshall the given XMLObject and append it as a child of the given parent element.\r
@@ -69,10 +97,13 @@ namespace xmltooling {
          * \r
          * @param xmlObject the XMLObject to be marshalled\r
          * @param parentElement the parent element to append the resulting DOM tree\r
+         * @param ctx       optional marshalling context\r
          * @return the marshalled element tree\r
+\r
          * @throws MarshallingException thrown if the given XMLObject can not be marshalled.\r
+         * @throws SignatureException thrown if a problem occurs during signature creation \r
          */\r
-        virtual DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement) const=0;\r
+        virtual DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx=NULL) const=0;\r
 \r
         /**\r
          * Retrieves a Marshaller using the key it was registered with.\r
diff --git a/xmltooling/signature/KeyInfo.h b/xmltooling/signature/KeyInfo.h
new file mode 100644 (file)
index 0000000..9648a3c
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file KeyInfo.h\r
+ * \r
+ * XMLObject representing XML Digital Signature, version 20020212, KeyInfo element. \r
+ */\r
+\r
+#if !defined(__xmltooling_keyinfo_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_keyinfo_h__\r
+\r
+#include <xmltooling/XMLObject.h>\r
+#include <xsec/dsig/DSIGKeyInfoList.hpp>\r
+\r
+namespace xmltooling {\r
+\r
+    /**\r
+     * XMLObject representing XML Digital Signature, version 20020212, KeyInfo element.\r
+     */\r
+    class XMLTOOL_API KeyInfo : public virtual XMLObject\r
+    {\r
+    public:\r
+        virtual ~KeyInfo() {}\r
+\r
+        /** Element local name */\r
+        static const XMLCh LOCAL_NAME[];\r
+\r
+        /**\r
+         * Returns immutable ds:KeyInfo information.\r
+         * \r
+         * @return the ds:KeyInfo information\r
+         */\r
+        virtual const DSIGKeyInfoList* getKeyInfo() const=0; \r
+\r
+        /**\r
+         * Returns mutable ds:KeyInfo information.\r
+         * \r
+         * @return the ds:KeyInfo information\r
+         */\r
+        virtual DSIGKeyInfoList* getKeyInfo()=0; \r
+        \r
+    protected:\r
+        KeyInfo() {}\r
+    };\r
+\r
+};\r
+\r
+#endif /* __xmltooling_keyinfo_h__ */\r
diff --git a/xmltooling/signature/Signature.h b/xmltooling/signature/Signature.h
new file mode 100644 (file)
index 0000000..fd219d6
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file Signature.h\r
+ * \r
+ * XMLObject representing XML Digital Signature, version 20020212, Signature element. \r
+ */\r
+\r
+#if !defined(__xmltooling_sig_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_sig_h__\r
+\r
+#include <xmltooling/XMLObject.h>\r
+#include <xmltooling/signature/SigningContext.h>\r
+\r
+namespace xmltooling {\r
+\r
+    /**\r
+     * XMLObject representing XML Digital Signature, version 20020212, Signature element.\r
+     * The default signature settings include Exclusive c14n w/o comments, SHA-1 digests,\r
+     * and RSA-SHA1 signing. \r
+     */\r
+    class XMLTOOL_API Signature : public virtual XMLObject\r
+    {\r
+    public:\r
+        virtual ~Signature() {}\r
+\r
+        /** Element prefix */\r
+        static const XMLCh PREFIX[];\r
+\r
+        /** Element local name */\r
+        static const XMLCh LOCAL_NAME[];\r
+\r
+        /**\r
+         * Gets the canonicalization method for the ds:SignedInfo element.\r
+         * \r
+         * @return the canonicalization method\r
+         */\r
+        virtual const XMLCh* getCanonicalizationMethod() const=0;\r
+        \r
+        /**\r
+         * Gets the signing algorithm for the signature.\r
+         * \r
+         * @return the signature algorithm\r
+         */\r
+        virtual const XMLCh* getSignatureAlgorithm() const=0;\r
+\r
+        /**\r
+         * Returns the ds:KeyInfo information attached to the signature.\r
+         * The Signature object must be marshalled before this will return anything.\r
+         * \r
+         * @return the ds:KeyInfo information\r
+         */\r
+        virtual const DSIGKeyInfoList* getKeyInfo() const=0; \r
+\r
+        /**\r
+         * Sets the canonicalization method for the ds:SignedInfo element\r
+         * \r
+         * @param c14n  the canonicalization method\r
+         */\r
+        virtual void setCanonicalizationMethod(const XMLCh* c14n)=0;\r
+        \r
+        /**\r
+         * Sets the signing algorithm for the signature.\r
+         * \r
+         * @param sm    the signature algorithm\r
+         */\r
+        virtual void setSignatureAlgorithm(const XMLCh* sm)=0;\r
+        \r
+        /**\r
+         * Applies an XML signature based on the supplied context.\r
+         * \r
+         * @param ctx   the signing context that determines the signature's content\r
+         * @throws SignatureException   thrown if the signing operation fails\r
+         */\r
+        virtual void sign(const SigningContext* ctx)=0;\r
+        \r
+    protected:\r
+        Signature() {}\r
+    };\r
+\r
+};\r
+\r
+#endif /* __xmltooling_sig_h__ */\r
diff --git a/xmltooling/signature/SigningContext.h b/xmltooling/signature/SigningContext.h
new file mode 100644 (file)
index 0000000..72648d6
--- /dev/null
@@ -0,0 +1,79 @@
+/*\r
+ *  Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file SigningContext.h\r
+ * \r
+ * Interface to signing process supplied by a signing application \r
+ */\r
+\r
+#if !defined(__xmltooling_signctx_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_signctx_h__\r
+\r
+#include <vector>\r
+#include <xsec/dsig/DSIGSignature.hpp>\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4250 4251 )\r
+#endif\r
+\r
+namespace xmltooling {\r
+\r
+    /**\r
+     * Interface to signing process supplied by a signing application\r
+     */\r
+    class XMLTOOL_API SigningContext\r
+    {\r
+        MAKE_NONCOPYABLE(SigningContext);\r
+    public:\r
+        virtual ~SigningContext() {}\r
+\r
+        /**\r
+         * Given a "blank" native signature, asks the context to define the\r
+         * appropriate signature transforms, references, etc.\r
+         * This method MAY attach ds:KeyInfo information, or a set of X.509\r
+         * certificates can be returned from the SigningContext::getX509Certificates()\r
+         * method instead.   \r
+         */\r
+        virtual void createSignature(DSIGSignature* sig) const=0;\r
+        \r
+        /**\r
+         * Gets a reference to a collection of certificates to append to\r
+         * the ds:KeyInfo element in a ds:X509Data chain.\r
+         * The certificate corresponding to the signing key SHOULD be\r
+         * first, followed by any additional intermediates to append. \r
+         */\r
+        virtual const std::vector<XSECCryptoX509*>& getX509Certificates() const=0;\r
+        \r
+        /**\r
+         * Gets the signing key to use.\r
+         * Must be compatible with the intended signature algorithm. Ownership of the key\r
+         * MUST be transferred to the caller.\r
+         */\r
+        virtual XSECCryptoKey* getSigningKey() const=0;\r
+        \r
+    protected:\r
+        SigningContext() {}\r
+    };\r
+\r
+};\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+\r
+#endif /* __xmltooling_signctx_h__ */\r
diff --git a/xmltooling/signature/impl/XMLSecSignature.cpp b/xmltooling/signature/impl/XMLSecSignature.cpp
new file mode 100644 (file)
index 0000000..1462ba6
--- /dev/null
@@ -0,0 +1,356 @@
+/*\r
+*  Copyright 2001-2006 Internet2\r
+ * \r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * XMLSecSignature.cpp\r
+ * \r
+ * Signature classes for XMLSec-based signature-handling\r
+ */\r
+\r
+#include "internal.h"\r
+#include "exceptions.h"\r
+#include "signature/impl/XMLSecSignature.h"\r
+#include "util/NDC.h"\r
+#include "util/XMLHelper.h"\r
+\r
+#include <log4cpp/Category.hh>\r
+#include <xercesc/framework/MemBufInputSource.hpp>\r
+#include <xercesc/framework/Wrapper4InputSource.hpp>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+#include <xsec/dsig/DSIGKeyInfoX509.hpp>\r
+#include <xsec/enc/XSECCryptoException.hpp>\r
+#include <xsec/framework/XSECException.hpp>\r
+\r
+using namespace xmltooling;\r
+using namespace log4cpp;\r
+using namespace std;\r
+\r
+const XMLCh xmltooling::Signature::LOCAL_NAME[] = {\r
+    chLatin_S, chLatin_i, chLatin_g, chLatin_n, chLatin_a, chLatin_t, chLatin_u, chLatin_r, chLatin_e, chNull\r
+}; \r
+\r
+const XMLCh xmltooling::Signature::PREFIX[] = {\r
+    chLatin_d, chLatin_s, chNull\r
+}; \r
+\r
+XMLSecSignatureImpl::~XMLSecSignatureImpl()\r
+{\r
+    // Release the associated signature.\r
+    if (m_signature)\r
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
+\r
+    XMLString::release(&m_c14n);\r
+    XMLString::release(&m_sm);\r
+}\r
+\r
+void XMLSecSignatureImpl::releaseDOM()\r
+{\r
+    // This should save off the DOM\r
+    UnknownElementImpl::releaseDOM();\r
+    \r
+    // Release the associated signature.\r
+    if (m_signature) {\r
+        XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(m_signature);\r
+        m_signature=NULL;\r
+    }\r
+}\r
+\r
+XMLObject* XMLSecSignatureImpl::clone() const\r
+{\r
+    XMLSecSignatureImpl* ret=new XMLSecSignatureImpl();\r
+\r
+    ret->m_c14n=XMLString::replicate(m_c14n);\r
+    ret->m_sm=XMLString::replicate(m_sm);\r
+\r
+    // If there's no XML locally, serialize this object into the new one, otherwise just copy it over.\r
+    if (m_xml.empty())\r
+        serialize(ret->m_xml);\r
+    else\r
+        ret->m_xml=m_xml;\r
+\r
+    return ret;\r
+}\r
+\r
+const DSIGKeyInfoList* XMLSecSignatureImpl::getKeyInfo() const\r
+{\r
+    return m_signature ? m_signature->getKeyInfoList() : NULL;\r
+}\r
+\r
+class _addcert : public std::binary_function<DSIGKeyInfoX509*,XSECCryptoX509*,void> {\r
+public:\r
+    void operator()(DSIGKeyInfoX509* bag, XSECCryptoX509* cert) const {\r
+        safeBuffer& buf=cert->getDEREncodingSB();\r
+        bag->appendX509Certificate(buf.sbStrToXMLCh());\r
+    }\r
+};\r
+\r
+void XMLSecSignatureImpl::sign(const SigningContext* ctx)\r
+{\r
+    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Signature");\r
+    log.debug("applying signature");\r
+\r
+    if (!m_signature)\r
+        throw SignatureException("Only a marshalled Signature object can be signed.");\r
+\r
+    try {\r
+        log.debug("creating signature content");\r
+        ctx->createSignature(m_signature);\r
+        const std::vector<XSECCryptoX509*>& certs=ctx->getX509Certificates();\r
+        if (!certs.empty()) {\r
+            DSIGKeyInfoX509* x509Data=m_signature->appendX509Data();\r
+            for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));\r
+        }\r
+        \r
+        log.debug("computing signature");\r
+        m_signature->setSigningKey(ctx->getSigningKey());\r
+        m_signature->sign();\r
+    }\r
+    catch(XSECException& e) {\r
+        auto_ptr_char temp(e.getMsg());\r
+        throw SignatureException(string("Caught an XMLSecurity exception while signing: ") + temp.get());\r
+    }\r
+    catch(XSECCryptoException& e) {\r
+        throw SignatureException(string("Caught an XMLSecurity exception while signing: ") + e.getMsg());\r
+    }\r
+}\r
+\r
+DOMElement* XMLSecSignatureMarshaller::marshall(XMLObject* xmlObject, DOMDocument* document, MarshallingContext* ctx) const\r
+{\r
+#ifdef _DEBUG\r
+    xmltooling::NDC ndc("marshall");\r
+#endif\r
+    \r
+    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Marshaller");\r
+    log.debug("marshalling ds:Signature");\r
+\r
+    XMLSecSignatureImpl* sig=dynamic_cast<XMLSecSignatureImpl*>(xmlObject);\r
+    if (!sig)\r
+        throw MarshallingException("Only objects of class XMLSecSignatureImpl can be marshalled.");\r
+    \r
+    DOMElement* cachedDOM=sig->getDOM();\r
+    if (cachedDOM) {\r
+        if (!document || document==cachedDOM->getOwnerDocument()) {\r
+            log.debug("Signature has a usable cached DOM, reusing it");\r
+            if (document)\r
+                setDocumentElement(cachedDOM->getOwnerDocument(),cachedDOM);\r
+            sig->releaseParentDOM(true);\r
+            return cachedDOM;\r
+        }\r
+        \r
+        // We have a DOM but it doesn't match the document we were given, so we import\r
+        // it into the new document.\r
+        cachedDOM=static_cast<DOMElement*>(document->importNode(cachedDOM, true));\r
+\r
+        try {\r
+            XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(sig->m_signature);\r
+            sig->m_signature=NULL;\r
+            sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
+                document, cachedDOM\r
+                );\r
+        }\r
+        catch(XSECException& e) {\r
+            auto_ptr_char temp(e.getMsg());\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
+        }\r
+        catch(XSECCryptoException& e) {\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
+        }\r
+\r
+        // Recache the DOM.\r
+        setDocumentElement(document, cachedDOM);\r
+        log.debug("caching imported DOM for Signature");\r
+        sig->setDOM(cachedDOM, false);\r
+        sig->releaseParentDOM(true);\r
+        return cachedDOM;\r
+    }\r
+    \r
+    // If we get here, we didn't have a usable DOM.\r
+    bool bindDocument=false;\r
+    if (sig->m_xml.empty()) {\r
+        // Fresh signature, so we just create an empty one.\r
+        log.debug("creating empty Signature element");\r
+        if (!document) {\r
+            document=DOMImplementationRegistry::getDOMImplementation(NULL)->createDocument();\r
+            bindDocument=true;\r
+        }\r
+        sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();\r
+        sig->m_signature->setDSIGNSPrefix(Signature::PREFIX);\r
+        cachedDOM=sig->m_signature->createBlankSignature(\r
+            document, sig->getCanonicalizationMethod(), sig->getSignatureAlgorithm()\r
+            );\r
+    }\r
+    else {\r
+        // We need to reparse the XML we saved off into a new DOM.\r
+        MemBufInputSource src(reinterpret_cast<const XMLByte*>(sig->m_xml.c_str()),sig->m_xml.length(),"XMLSecSignatureImpl");\r
+        Wrapper4InputSource dsrc(&src,false);\r
+        log.debug("parsing Signature XML back into DOM tree");\r
+        DOMDocument* internalDoc=XMLToolingInternalConfig::getInternalConfig().m_parserPool->parse(dsrc);\r
+        if (document) {\r
+            // The caller insists on using his own document, so we now have to import the thing\r
+            // into it. Then we're just dumping the one we built.\r
+            log.debug("reimporting new DOM into caller-supplied document");\r
+            cachedDOM=static_cast<DOMElement*>(document->importNode(internalDoc->getDocumentElement(), true));\r
+            internalDoc->release();\r
+        }\r
+        else {\r
+            // We just bind the document we built to the object as the result.\r
+            cachedDOM=static_cast<DOMElement*>(internalDoc->getDocumentElement());\r
+            document=internalDoc;\r
+            bindDocument=true;\r
+        }\r
+\r
+        // Now reload the signature from the DOM.\r
+        try {\r
+            sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
+                document, cachedDOM\r
+                );\r
+        }\r
+        catch(XSECException& e) {\r
+            if (bindDocument)\r
+                document->release();\r
+            auto_ptr_char temp(e.getMsg());\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
+        }\r
+        catch(XSECCryptoException& e) {\r
+            if (bindDocument)\r
+                document->release();\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
+        }\r
+    }\r
+    \r
+    // Recache the DOM and clear the serialized copy.\r
+    setDocumentElement(document, cachedDOM);\r
+    log.debug("caching DOM for Signature (document is %sbound)", bindDocument ? "" : "not ");\r
+    sig->setDOM(cachedDOM, bindDocument);\r
+    sig->releaseParentDOM(true);\r
+    sig->m_xml.erase();\r
+    return cachedDOM;\r
+}\r
+\r
+DOMElement* XMLSecSignatureMarshaller::marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx) const\r
+{\r
+#ifdef _DEBUG\r
+    xmltooling::NDC ndc("marshall");\r
+#endif\r
+    \r
+    Category& log=Category::getInstance(XMLTOOLING_LOGCAT".Marshaller");\r
+    log.debug("marshalling ds:Signature");\r
+\r
+    XMLSecSignatureImpl* sig=dynamic_cast<XMLSecSignatureImpl*>(xmlObject);\r
+    if (!sig)\r
+        throw MarshallingException("Only objects of class XMLSecSignatureImpl can be marshalled.");\r
+    \r
+    DOMElement* cachedDOM=sig->getDOM();\r
+    if (cachedDOM) {\r
+        if (parentElement->getOwnerDocument()==cachedDOM->getOwnerDocument()) {\r
+            log.debug("Signature has a usable cached DOM, reusing it");\r
+            parentElement->appendChild(cachedDOM);\r
+            sig->releaseParentDOM(true);\r
+            return cachedDOM;\r
+        }\r
+        \r
+        // We have a DOM but it doesn't match the document we were given, so we import\r
+        // it into the new document.\r
+        cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(cachedDOM, true));\r
+\r
+        try {\r
+            XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->releaseSignature(sig->m_signature);\r
+            sig->m_signature=NULL;\r
+            sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
+                parentElement->getOwnerDocument(), cachedDOM\r
+                );\r
+        }\r
+        catch(XSECException& e) {\r
+            auto_ptr_char temp(e.getMsg());\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
+        }\r
+        catch(XSECCryptoException& e) {\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
+        }\r
+\r
+        // Recache the DOM.\r
+        parentElement->appendChild(cachedDOM);\r
+        log.debug("caching imported DOM for Signature");\r
+        sig->setDOM(cachedDOM, false);\r
+        sig->releaseParentDOM(true);\r
+        return cachedDOM;\r
+    }\r
+    \r
+    // If we get here, we didn't have a usable DOM.\r
+    if (sig->m_xml.empty()) {\r
+        // Fresh signature, so we just create an empty one.\r
+        log.debug("creating empty Signature element");\r
+        sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignature();\r
+        sig->m_signature->setDSIGNSPrefix(Signature::PREFIX);\r
+        cachedDOM=sig->m_signature->createBlankSignature(\r
+            parentElement->getOwnerDocument(), sig->getCanonicalizationMethod(), sig->getSignatureAlgorithm()\r
+            );\r
+    }\r
+    else {\r
+        MemBufInputSource src(reinterpret_cast<const XMLByte*>(sig->m_xml.c_str()),sig->m_xml.length(),"XMLSecSignatureImpl");\r
+        Wrapper4InputSource dsrc(&src,false);\r
+        log.debug("parsing XML back into DOM tree");\r
+        DOMDocument* internalDoc=XMLToolingInternalConfig::getInternalConfig().m_parserPool->parse(dsrc);\r
+        \r
+        log.debug("reimporting new DOM into caller-supplied document");\r
+        cachedDOM=static_cast<DOMElement*>(parentElement->getOwnerDocument()->importNode(internalDoc->getDocumentElement(), true));\r
+        internalDoc->release();\r
+\r
+        // Now reload the signature from the DOM.\r
+        try {\r
+            sig->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
+                parentElement->getOwnerDocument(), cachedDOM\r
+                );\r
+        }\r
+        catch(XSECException& e) {\r
+            auto_ptr_char temp(e.getMsg());\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
+        }\r
+        catch(XSECCryptoException& e) {\r
+            throw MarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
+        }\r
+    }\r
+\r
+    // Recache the DOM and clear the serialized copy.\r
+    parentElement->appendChild(cachedDOM);\r
+    log.debug("caching DOM for Signature");\r
+    sig->setDOM(cachedDOM, false);\r
+    sig->releaseParentDOM(true);\r
+    sig->m_xml.erase();\r
+    return cachedDOM;\r
+}\r
+\r
+XMLObject* XMLSecSignatureUnmarshaller::unmarshall(DOMElement* element, bool bindDocument) const\r
+{\r
+    Category::getInstance(XMLTOOLING_LOGCAT".Unmarshaller").debug("unmarshalling ds:Signature");\r
+\r
+    auto_ptr<XMLSecSignatureImpl> ret(new XMLSecSignatureImpl());\r
+    try {\r
+        ret->m_signature=XMLToolingInternalConfig::getInternalConfig().m_xsecProvider->newSignatureFromDOM(\r
+            element->getOwnerDocument(), element\r
+            );\r
+    }\r
+    catch(XSECException& e) {\r
+        auto_ptr_char temp(e.getMsg());\r
+        throw UnmarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + temp.get());\r
+    }\r
+    catch(XSECCryptoException& e) {\r
+        throw UnmarshallingException(string("Caught an XMLSecurity exception while loading signature: ") + e.getMsg());\r
+    }\r
+\r
+    ret->setDOM(element, bindDocument);\r
+    return ret.release();\r
+}\r
diff --git a/xmltooling/signature/impl/XMLSecSignature.h b/xmltooling/signature/impl/XMLSecSignature.h
new file mode 100644 (file)
index 0000000..1bc0c1f
--- /dev/null
@@ -0,0 +1,132 @@
+/*\r
+*  Copyright 2001-2006 Internet2\r
+ * \r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/**\r
+ * @file XMLSecSignature.h\r
+ * \r
+ * Signature classes for XMLSec-based signature-handling\r
+ */\r
+\r
+#if !defined(__xmltooling_xmlsecsig_h__) && !defined(XMLTOOLING_NO_XMLSEC)\r
+#define __xmltooling_xmlsecsig_h__\r
+\r
+#include "internal.h"\r
+#include "impl/UnknownElement.h"\r
+#include "signature/Signature.h"\r
+#include "util/XMLConstants.h"\r
+\r
+#include <string>\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4250 4251 )\r
+#endif\r
+\r
+namespace xmltooling {\r
+\r
+    /**\r
+     * XMLObject representing XML Digital Signature, version 20020212, Signature element.\r
+     * Manages an Apache XML Signature object and the associated DOM.  \r
+     */\r
+    class XMLTOOL_DLLLOCAL XMLSecSignatureImpl : public UnknownElementImpl, public virtual Signature\r
+    {\r
+    public:\r
+        XMLSecSignatureImpl() : UnknownElementImpl(XMLConstants::XMLSIG_NS, Signature::LOCAL_NAME),\r
+            m_signature(NULL), m_c14n(NULL), m_sm(NULL) {}\r
+        virtual ~XMLSecSignatureImpl();\r
+        \r
+        void releaseDOM();\r
+        XMLObject* clone() const;\r
+\r
+        // Getters\r
+        const XMLCh* getCanonicalizationMethod() const { return m_c14n ? m_c14n : DSIGConstants::s_unicodeStrURIEXC_C14N_NOC; }\r
+        const XMLCh* getSignatureAlgorithm() const { return m_sm ? m_sm : DSIGConstants::s_unicodeStrURIRSA_SHA1; }\r
+        const DSIGKeyInfoList* getKeyInfo() const;\r
+\r
+        // Setters\r
+        void setCanonicalizationMethod(const XMLCh* c14n) { m_c14n = prepareForAssignment(m_c14n,c14n); }\r
+        void setSignatureAlgorithm(const XMLCh* sm) { m_sm = prepareForAssignment(m_sm,sm); }\r
+\r
+        void sign(const SigningContext* ctx);\r
+\r
+    private:\r
+        DSIGSignature* m_signature;\r
+        XMLCh* m_c14n;\r
+        XMLCh* m_sm;\r
+\r
+        friend class XMLTOOL_DLLLOCAL XMLSecSignatureMarshaller;\r
+        friend class XMLTOOL_DLLLOCAL XMLSecSignatureUnmarshaller;\r
+    };\r
+\r
+    /**\r
+     * Factory for XMLSecSignatureImpl objects\r
+     */\r
+    class XMLTOOL_DLLLOCAL XMLSecSignatureBuilder : public virtual XMLObjectBuilder\r
+    {\r
+    public:\r
+        /**\r
+         * @see XMLObjectBuilder::buildObject()\r
+         */\r
+        XMLObject* buildObject() const {\r
+            return new XMLSecSignatureImpl();\r
+        }\r
+    };\r
+\r
+    /**\r
+     * Marshaller for XMLSecSignatureImpl objects\r
+     */\r
+    class XMLTOOL_DLLLOCAL XMLSecSignatureMarshaller : public virtual Marshaller\r
+    {\r
+    public:\r
+        /**\r
+         * @see Marshaller::marshall(XMLObject*,DOMDocument*, const MarshallingContext*)\r
+         */\r
+        DOMElement* marshall(XMLObject* xmlObject, DOMDocument* document=NULL, MarshallingContext* ctx=NULL) const;\r
+\r
+        /**\r
+         * @see Marshaller::marshall(XMLObject*,DOMElement*, const MarshallingContext* ctx)\r
+         */\r
+        DOMElement* marshall(XMLObject* xmlObject, DOMElement* parentElement, MarshallingContext* ctx=NULL) const;\r
+        \r
+    protected:\r
+        void setDocumentElement(DOMDocument* document, DOMElement* element) const {\r
+            DOMElement* documentRoot = document->getDocumentElement();\r
+            if (documentRoot)\r
+                document->replaceChild(documentRoot, element);\r
+            else\r
+                document->appendChild(element);\r
+        }\r
+    };\r
+\r
+    /**\r
+     * Unmarshaller for XMLSecSignatureImpl objects\r
+     */\r
+    class XMLTOOL_DLLLOCAL XMLSecSignatureUnmarshaller : public virtual Unmarshaller\r
+    {\r
+    public:\r
+        /**\r
+         * @see Unmarshaller::unmarshall()\r
+         */\r
+        XMLObject* unmarshall(DOMElement* element, bool bindDocument=false) const;\r
+    };\r
+\r
+};\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+\r
+#endif /* __xmltooling_xmlsecsig_h__ */\r
index 7401037..3eb039d 100644 (file)
@@ -166,7 +166,7 @@ bool ParserPool::loadCatalog(const XMLCh* pathname)
         \r
         // Check root element.\r
         const DOMElement* root=doc->getDocumentElement();\r
-        if (!XMLHelper::isElementNamed(root,CATALOG_NS,catalog)) {\r
+        if (!XMLHelper::isNodeNamed(root,CATALOG_NS,catalog)) {\r
             auto_ptr_char temp(pathname);\r
             log.error("unknown root element, failed to load XML catalog from %s", temp.get());\r
             return false;\r
index c1ad4fe..99697e6 100644 (file)
@@ -87,15 +87,15 @@ namespace xmltooling {
         static DOMElement* appendChildElement(DOMElement* parentElement, DOMElement* childElement);\r
         \r
         /**\r
-         * Checks the qualified name of an element.\r
+         * Checks the qualified name of a node.\r
          * \r
-         * @param e     element to check\r
+         * @param n     node to check\r
          * @param ns    namespace to compare with\r
          * @param local local name to compare with\r
-         * @return  true iff the element's qualified name matches the other parameters\r
+         * @return  true iff the node's qualified name matches the other parameters\r
          */\r
-        static bool isElementNamed(const DOMElement* e, const XMLCh* ns, const XMLCh* local) {\r
-            return (e && XMLString::equals(ns,e->getNamespaceURI()) && XMLString::equals(local,e->getLocalName()));\r
+        static bool isNodeNamed(const DOMNode* n, const XMLCh* ns, const XMLCh* local) {\r
+            return (n && XMLString::equals(local,n->getLocalName()) && XMLString::equals(ns,n->getNamespaceURI()));\r
         }\r
 \r
         /**\r
index dd90a19..9de1579 100644 (file)
@@ -238,6 +238,8 @@ namespace xmltooling {
             removeParent(*_Where);
             if (m_list)
                 removeChild(*_Where);
+            else
+                delete *_Where.m_iter;
             return m_container.erase(_Where.m_iter);
         }
 
@@ -246,6 +248,8 @@ namespace xmltooling {
                 removeParent(*i);
                 if (m_list)
                     removeChild(*i);
+                else
+                    delete *i.m_iter;
             }
             return m_container.erase(_First,_Last);
         }
index 705d8f0..deafcaa 100644 (file)
                                        >\r
                                </File>\r
                        </Filter>\r
+                       <Filter\r
+                               Name="signature"\r
+                               >\r
+                               <Filter\r
+                                       Name="impl"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\signature\impl\XMLSecSignature.cpp"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
+                       </Filter>\r
                </Filter>\r
                <Filter\r
                        Name="Header Files"\r
                                        >\r
                                </File>\r
                        </Filter>\r
+                       <Filter\r
+                               Name="signature"\r
+                               >\r
+                               <File\r
+                                       RelativePath=".\signature\KeyInfo.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\signature\Signature.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\signature\SigningContext.h"\r
+                                       >\r
+                               </File>\r
+                               <Filter\r
+                                       Name="impl"\r
+                                       >\r
+                                       <File\r
+                                               RelativePath=".\signature\impl\XMLSecSignature.h"\r
+                                               >\r
+                                       </File>\r
+                               </Filter>\r
+                       </Filter>\r
                </Filter>\r
                <Filter\r
                        Name="Resource Files"\r
index da0ecfb..3e55771 100644 (file)
@@ -30,9 +30,9 @@ public:
     }\r
 \r
     void tearDown() {\r
-        XMLObjectBuilder::deregisterDefaultBuilder();\r
-        Marshaller::deregisterDefaultMarshaller();\r
-        Unmarshaller::deregisterDefaultUnmarshaller();\r
+        //XMLObjectBuilder::deregisterDefaultBuilder();\r
+        //Marshaller::deregisterDefaultMarshaller();\r
+        //Unmarshaller::deregisterDefaultUnmarshaller();\r
     }\r
 \r
     void testComplexUnmarshalling() {\r
index c3243c9..92f35d3 100644 (file)
@@ -10,6 +10,7 @@ endif
 xmltoolingtest_h = \
     ComplexXMLObjectTest.h \
     MarshallingTest.h \
+    Signature.h \
     UnknownTest.h \
     UnmarshallingTest.h \
     xmltoolingtest.h
diff --git a/xmltoolingtest/SignatureTest.h b/xmltoolingtest/SignatureTest.h
new file mode 100644 (file)
index 0000000..2087c4e
--- /dev/null
@@ -0,0 +1,133 @@
+/*\r
+ *  Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "XMLObjectBaseTestCase.h"\r
+\r
+#include <fstream>\r
+#include <openssl/pem.h>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+#include <xsec/dsig/DSIGReference.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
+#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
+\r
+class TestContext : public SigningContext\r
+{\r
+    XSECCryptoKey* m_key;\r
+    vector<XSECCryptoX509*> m_certs;\r
+    XMLCh* m_uri;\r
+    \r
+public:\r
+    TestContext(const XMLCh* uri) {\r
+        string keypath=data_path + "key.pem";\r
+        BIO* in=BIO_new(BIO_s_file_internal());\r
+        if (in && BIO_read_filename(in,keypath.c_str())>0) {\r
+            EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);\r
+            if (pkey) {\r
+                m_key=new OpenSSLCryptoKeyRSA(pkey);\r
+                EVP_PKEY_free(pkey);\r
+            }\r
+        }\r
+        if (in) BIO_free(in);\r
+        TS_ASSERT(m_key!=NULL);\r
+\r
+        string certpath=data_path + "cert.pem";\r
+        in=BIO_new(BIO_s_file_internal());\r
+        if (in && BIO_read_filename(in,certpath.c_str())>0) {\r
+            X509* x=NULL;\r
+            while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) {\r
+                m_certs.push_back(new OpenSSLCryptoX509(x));\r
+                X509_free(x);\r
+            }\r
+        }\r
+        if (in) BIO_free(in);\r
+        TS_ASSERT(m_certs.size()>0);\r
+        \r
+        m_uri=XMLString::replicate(uri);\r
+    }\r
+    \r
+    virtual ~TestContext() {\r
+        delete m_key;\r
+        for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
+        XMLString::release(&m_uri);\r
+    }\r
+\r
+    void createSignature(DSIGSignature* sig) const {\r
+        DSIGReference* ref=sig->createReference(m_uri);\r
+        ref->appendEnvelopedSignatureTransform();\r
+        ref->appendCanonicalizationTransform(CANON_C14NE_NOC);\r
+    }\r
+    \r
+    const std::vector<XSECCryptoX509*>& getX509Certificates() const { return m_certs; }\r
+    XSECCryptoKey* getSigningKey() const { return m_key->clone(); }\r
+};\r
+\r
+class SignatureTest : public CxxTest::TestSuite {\r
+    QName m_qname;\r
+public:\r
+    SignatureTest() : m_qname(SimpleXMLObject::NAMESPACE,SimpleXMLObject::LOCAL_NAME) {}\r
+\r
+    void setUp() {\r
+        XMLObjectBuilder::registerBuilder(m_qname, new SimpleXMLObjectBuilder());\r
+        Marshaller::registerMarshaller(m_qname, new SimpleXMLObjectMarshaller());\r
+        Unmarshaller::registerUnmarshaller(m_qname, new SimpleXMLObjectUnmarshaller());\r
+    }\r
+\r
+    void tearDown() {\r
+        XMLObjectBuilder::deregisterBuilder(m_qname);\r
+        Marshaller::deregisterMarshaller(m_qname);\r
+        Unmarshaller::deregisterUnmarshaller(m_qname);\r
+    }\r
+\r
+    void testSignature() {\r
+        TS_TRACE("testSignature");\r
+\r
+        const XMLObjectBuilder* b=XMLObjectBuilder::getBuilder(m_qname);\r
+        TS_ASSERT(b!=NULL);\r
+        \r
+        auto_ptr<SimpleXMLObject> sxObject(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        TS_ASSERT(sxObject.get()!=NULL);\r
+        VectorOf(SimpleXMLObject) kids=sxObject->getSimpleXMLObjects();\r
+        kids.push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        kids.push_back(dynamic_cast<SimpleXMLObject*>(b->buildObject()));\r
+        \r
+        // Test some collection stuff\r
+        auto_ptr_XMLCh foo("Foo");\r
+        auto_ptr_XMLCh bar("Bar");\r
+        kids.begin()->setId(foo.get());\r
+        kids[1]->setValue(bar.get());\r
+        \r
+        // Append a Signature.\r
+        Signature* sig=dynamic_cast<Signature*>(XMLObjectBuilder::buildObject(QName(XMLConstants::XMLSIG_NS,Signature::LOCAL_NAME)));\r
+        sxObject->setSignature(sig);\r
+        \r
+        // Signing context for the whole document.\r
+        TestContext tc(&chNull);\r
+        MarshallingContext mctx(sig,&tc);\r
+        DOMElement* rootElement = Marshaller::getMarshaller(sxObject.get())->marshall(sxObject.get(),(DOMDocument*)NULL,&mctx);\r
+        \r
+        string buf;\r
+        XMLHelper::serialize(rootElement, buf);\r
+        TS_TRACE(buf.c_str());\r
+\r
+        istringstream in(buf);\r
+        DOMDocument* doc=nonvalidatingPool->parse(in);\r
+        const Unmarshaller* u = Unmarshaller::getUnmarshaller(doc->getDocumentElement());\r
+        auto_ptr<SimpleXMLObject> sxObject2(dynamic_cast<SimpleXMLObject*>(u->unmarshall(doc->getDocumentElement(),true)));\r
+        TS_ASSERT(sxObject2.get()!=NULL);\r
+        TS_ASSERT(sxObject2->getSignature()!=NULL);\r
+    }\r
+\r
+};\r
index 28aa716..4085128 100644 (file)
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/io/AbstractXMLObjectMarshaller.h>
 #include <xmltooling/io/AbstractXMLObjectUnmarshaller.h>
+#ifndef XMLTOOLING_NO_XMLSEC
+    #include <xmltooling/signature/Signature.h>
+#endif
 #include <xmltooling/util/ParserPool.h>
-#include <xmltooling/util/XMLObjectChildrenList.h>
+#include <xmltooling/util/XMLConstants.h>
 #include <xmltooling/util/XMLHelper.h>
+#include <xmltooling/util/XMLObjectChildrenList.h>
 
 using namespace xmltooling;
 using namespace std;
@@ -47,7 +51,11 @@ public:
     static const XMLCh LOCAL_NAME[];
     static const XMLCh ID_ATTRIB_NAME[];
 
-    SimpleXMLObject() : AbstractDOMCachingXMLObject(NAMESPACE, LOCAL_NAME, NAMESPACE_PREFIX), m_id(NULL), m_value(NULL) {}
+    SimpleXMLObject() : AbstractDOMCachingXMLObject(NAMESPACE, LOCAL_NAME, NAMESPACE_PREFIX), m_id(NULL), m_value(NULL) {
+        m_children.push_back(NULL);
+        m_signature=m_children.begin();
+    }
+
     virtual ~SimpleXMLObject() {
         XMLString::release(&m_id);
         XMLString::release(&m_value);
@@ -58,7 +66,17 @@ public:
 
     const XMLCh* getValue() const { return m_value; }
     void setValue(const XMLCh* value) { m_value=prepareForAssignment(m_value,value); }
-    
+
+#ifndef XMLTOOLING_NO_XMLSEC    
+    Signature* getSignature() const {
+        return dynamic_cast<Signature*>(*m_signature);
+    }
+
+    void setSignature(Signature* sig) {
+        *m_signature=prepareForAssignment(*m_signature,sig);
+    }
+#endif
+
     VectorOf(SimpleXMLObject) getSimpleXMLObjects() {
         return VectorOf(SimpleXMLObject)(this, m_simples, &m_children, m_children.end());
     }
@@ -83,6 +101,7 @@ private:
     XMLCh* m_id;
     XMLCh* m_value;
     vector<SimpleXMLObject*> m_simples;
+    list<XMLObject*>::iterator m_signature;
 };
 
 class SimpleXMLObjectBuilder : public XMLObjectBuilder
@@ -123,27 +142,24 @@ public:
     SimpleXMLObjectUnmarshaller() {}
 
 private:
-    void processChildElement(XMLObject& parentXMLObject, XMLObject* childXMLObject) const {
+    void processChildElement(XMLObject& parentXMLObject, XMLObject* childXMLObject, const DOMElement* root) const {
         SimpleXMLObject& simpleXMLObject = dynamic_cast<SimpleXMLObject&>(parentXMLObject);
 
-        SimpleXMLObject* child = dynamic_cast<SimpleXMLObject*>(childXMLObject);
-        if (child) {
-            simpleXMLObject.getSimpleXMLObjects().push_back(child);
-        }
-        else {
+        if (XMLHelper::isNodeNamed(root, SimpleXMLObject::NAMESPACE, SimpleXMLObject::LOCAL_NAME))
+            simpleXMLObject.getSimpleXMLObjects().push_back(dynamic_cast<SimpleXMLObject*>(childXMLObject));
+        else if (XMLHelper::isNodeNamed(root, XMLConstants::XMLSIG_NS, Signature::LOCAL_NAME))
+            simpleXMLObject.setSignature(dynamic_cast<Signature*>(childXMLObject));
+        else
             throw UnmarshallingException("Unknown child element cannot be added to parent object.");
-        }
     }
 
     void processAttribute(XMLObject& xmlObject, const DOMAttr* attribute) const {
         SimpleXMLObject& simpleXMLObject = dynamic_cast<SimpleXMLObject&>(xmlObject);
 
-        if (XMLString::equals(attribute->getLocalName(),SimpleXMLObject::ID_ATTRIB_NAME)) {
+        if (XMLHelper::isNodeNamed(attribute, NULL, SimpleXMLObject::ID_ATTRIB_NAME))
             simpleXMLObject.setId(attribute->getValue());
-        }
-        else {
+        else
             throw UnmarshallingException("Unknown attribute cannot be processed by parent object.");
-        }
     }
 
     void processElementContent(XMLObject& xmlObject, const XMLCh* elementContent) const {
@@ -240,7 +256,7 @@ private:
         throw UnmarshallingException("Failed to locate WildcardObjectBuilder for element.");
     }
 
-    void processChildElement(XMLObject& parentXMLObject, XMLObject* childXMLObject) const {
+    void processChildElement(XMLObject& parentXMLObject, XMLObject* childXMLObject, const DOMElement* root) const {
         WildcardXMLObject& wcXMLObject = dynamic_cast<WildcardXMLObject&>(parentXMLObject);
 
         wcXMLObject.getXMLObjects().push_back(childXMLObject);
diff --git a/xmltoolingtest/data/cert.pem b/xmltoolingtest/data/cert.pem
new file mode 100644 (file)
index 0000000..e8261f3
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICjzCCAfigAwIBAgIJAKk8t1hYcMkhMA0GCSqGSIb3DQEBBAUAMDoxCzAJBgNV
+BAYTAlVTMRIwEAYDVQQKEwlJbnRlcm5ldDIxFzAVBgNVBAMTDnNwLmV4YW1wbGUu
+b3JnMB4XDTA1MDYyMDE1NDgzNFoXDTMyMTEwNTE1NDgzNFowOjELMAkGA1UEBhMC
+VVMxEjAQBgNVBAoTCUludGVybmV0MjEXMBUGA1UEAxMOc3AuZXhhbXBsZS5vcmcw
+gZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANlZ1L1mKzYbUVKiMQLhZlfGDyYa
+/jjCiaXP0WhLNgvJpOTeajvsrApYNnFX5MLNzuC3NeQIjXUNLN2Yo2MCSthBIOL5
+qE5dka4z9W9zytoflW1LmJ8vXpx8Ay/meG4z//J5iCpYVEquA0xl28HUIlownZUF
+7w7bx0cF/02qrR23AgMBAAGjgZwwgZkwHQYDVR0OBBYEFJZiO1qsyAyc3HwMlL9p
+JpN6fbGwMGoGA1UdIwRjMGGAFJZiO1qsyAyc3HwMlL9pJpN6fbGwoT6kPDA6MQsw
+CQYDVQQGEwJVUzESMBAGA1UEChMJSW50ZXJuZXQyMRcwFQYDVQQDEw5zcC5leGFt
+cGxlLm9yZ4IJAKk8t1hYcMkhMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQAD
+gYEAMFq/UeSQyngE0GpZueyD2UW0M358uhseYOgGEIfm+qXIFQF6MYwNoX7WFzhC
+LJZ2E6mEvZZFHCHUtl7mGDvsRwgZ85YCtRbvleEpqfgNQToto9pLYe+X6vvH9Z6p
+gmYsTmak+kxO93JprrOd9xp8aZPMEprL7VCdrhbZEfyYER0=
+-----END CERTIFICATE-----
diff --git a/xmltoolingtest/data/key.pem b/xmltoolingtest/data/key.pem
new file mode 100644 (file)
index 0000000..5149449
--- /dev/null
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDZWdS9Zis2G1FSojEC4WZXxg8mGv44womlz9FoSzYLyaTk3mo7
+7KwKWDZxV+TCzc7gtzXkCI11DSzdmKNjAkrYQSDi+ahOXZGuM/Vvc8raH5VtS5if
+L16cfAMv5nhuM//yeYgqWFRKrgNMZdvB1CJaMJ2VBe8O28dHBf9Nqq0dtwIDAQAB
+AoGAKsaVKdlLs9BYhuzIvIpju+6M2LEDS2Rt9qYZzm7O6i77NtfXDIgdq8OEo3Xq
+3bPnfS5Retl8DYdURyBdN4Uh+WR/BUWQjBvOaJLEEdxvuAaLyAjniVREwkc2rXTZ
+xoYYFL/XMyAEt/ye2ZbTw2u5R2i7HCYdddZWMkP1+Vabg8ECQQD7VJXWy8KFiyeC
+thJiVqG/h5IO0y25dId/n81sW2B55eK0c4+IVsqc0a45/U/y2y1wtNBmIEQQn9yY
+pDtWwzVRAkEA3WOgmvxFGTI5V1K5CLCCZzQIUYpzQDQvBu2sKYuy8dK2BMEGe9Zw
+cKVyZJuDKHBvrVI5G6CqkHuFD2PwDvwAhwJBAPdfbM/q4/4/VddAz918uV1j2a2/
+y3yDJq7GIhHp6o5wZ3AHYhnmmyw48YxgOGWntxT80zYBwhy+zAhtdX5TStECQEKL
+drP/TfnD2e6Ag/Ozso642iNAXWIYDWakvBIE1rXPYzzMlFlW3JdPc7H/+I2INlk/
+lMDUK1CggB9fJ8IpRzMCQQDQmqpWZtH6eaMAN6b/9WBdVzqzpCeTWFlL/SwhVbzI
+s+k2zvC4HEAK9Y199g6SHVTQMEAE49wfhhCpY0JdCsQ/
+-----END RSA PRIVATE KEY-----
index 54abfad..5703d4c 100644 (file)
@@ -62,7 +62,7 @@
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="xerces-c_2D.lib"\r
+                               AdditionalDependencies="xerces-c_2D.lib xsec_1D.lib libeay32_0_9_8D.lib"\r
                                LinkIncremental="2"\r
                                GenerateDebugInformation="true"\r
                                SubSystem="1"\r
                        />\r
                        <Tool\r
                                Name="VCLinkerTool"\r
-                               AdditionalDependencies="xerces-c_2.lib"\r
+                               AdditionalDependencies="xerces-c_2.lib xsec_1.lib libeay32_0_9_8.lib"\r
                                LinkIncremental="1"\r
                                GenerateDebugInformation="true"\r
                                SubSystem="1"\r
                                >\r
                        </File>\r
                        <File\r
+                               RelativePath=".\SignatureTest.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\UnknownTest.cpp"\r
                                >\r
                        </File>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                </FileConfiguration>\r
                        </File>\r
                        <File\r
+                               RelativePath=".\SignatureTest.h"\r
+                               >\r
+                               <FileConfiguration\r
+                                       Name="Debug|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                               <FileConfiguration\r
+                                       Name="Release|Win32"\r
+                                       >\r
+                                       <Tool\r
+                                               Name="VCCustomBuildTool"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\UnknownTest.h"\r
                                >\r
                                <FileConfiguration\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r
                                        >\r
                                        <Tool\r
                                                Name="VCCustomBuildTool"\r
-                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;&#x0D;&#x0A;"\r
+                                               CommandLine="\perl\bin\perl.exe -w \cxxtest\cxxtestgen.pl --part --have-eh --have-std --abort-on-fail -o &quot;$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
                                                Outputs="&quot;$(InputName)&quot;.cpp"\r
                                        />\r
                                </FileConfiguration>\r