MessageEncoder, ArtifactMap, and SAML 1.x encoder classes.
authorScott Cantor <cantor.2@osu.edu>
Tue, 26 Sep 2006 19:32:50 +0000 (19:32 +0000)
committerScott Cantor <cantor.2@osu.edu>
Tue, 26 Sep 2006 19:32:50 +0000 (19:32 +0000)
18 files changed:
.project
saml/Makefile.am
saml/SAMLConfig.cpp
saml/SAMLConfig.h
saml/binding/ArtifactMap.h [new file with mode: 0644]
saml/binding/MessageEncoder.h [new file with mode: 0644]
saml/binding/impl/ArtifactMap.cpp [new file with mode: 0644]
saml/binding/impl/MessageEncoder.cpp [new file with mode: 0644]
saml/exceptions.h
saml/saml.vcproj
saml/saml1/binding/SAML1ArtifactEncoder.h [new file with mode: 0644]
saml/saml1/binding/SAML1POSTEncoder.h [new file with mode: 0644]
saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp [new file with mode: 0644]
saml/saml1/binding/impl/SAML1POSTEncoder.cpp [new file with mode: 0644]
saml/saml2/metadata/impl/SignatureMetadataFilter.cpp
samltest/ArtifactMapTest.h [new file with mode: 0644]
samltest/Makefile.am
samltest/samltest.vcproj

index 22f4aa1..5a45fbb 100644 (file)
--- a/.project
+++ b/.project
                                        <value>org.eclipse.cdt.core.MakeErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;org.eclipse.cdt.core.VCErrorParser;</value>\r
                                </dictionary>\r
                                <dictionary>\r
-                                       <key>org.eclipse.cdt.make.core.enableAutoBuild</key>\r
-                                       <value>false</value>\r
-                               </dictionary>\r
-                               <dictionary>\r
                                        <key>org.eclipse.cdt.make.core.environment</key>\r
                                        <value></value>\r
                                </dictionary>\r
                                <dictionary>\r
-                                       <key>org.eclipse.cdt.make.core.enableFullBuild</key>\r
-                                       <value>true</value>\r
+                                       <key>org.eclipse.cdt.make.core.enableAutoBuild</key>\r
+                                       <value>false</value>\r
                                </dictionary>\r
                                <dictionary>\r
                                        <key>org.eclipse.cdt.make.core.build.target.inc</key>\r
                                        <value>all</value>\r
                                </dictionary>\r
                                <dictionary>\r
-                                       <key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>\r
+                                       <key>org.eclipse.cdt.make.core.enableFullBuild</key>\r
                                        <value>true</value>\r
                                </dictionary>\r
                                <dictionary>\r
-                                       <key>org.eclipse.cdt.make.core.build.target.clean</key>\r
-                                       <value>clean</value>\r
+                                       <key>org.eclipse.cdt.make.core.enabledIncrementalBuild</key>\r
+                                       <value>true</value>\r
                                </dictionary>\r
                                <dictionary>\r
                                        <key>org.eclipse.cdt.make.core.build.command</key>\r
                                        <value>make</value>\r
                                </dictionary>\r
                                <dictionary>\r
+                                       <key>org.eclipse.cdt.make.core.build.target.clean</key>\r
+                                       <value>clean</value>\r
+                               </dictionary>\r
+                               <dictionary>\r
                                        <key>org.eclipse.cdt.make.core.enableCleanBuild</key>\r
                                        <value>true</value>\r
                                </dictionary>\r
index f9e6af3..40d2744 100644 (file)
@@ -31,6 +31,8 @@ libsamlinclude_HEADERS = \
        SAMLConfig.h
 
 samlbindinclude_HEADERS = \
+       binding/ArtifactMap.h \
+       binding/MessageEncoder.h \
        binding/SAMLArtifact.h
 
 encinclude_HEADERS = \
@@ -56,6 +58,8 @@ saml1coreinclude_HEADERS = \
        saml1/core/Protocols.h
 
 saml1bindinclude_HEADERS = \
+       saml1/binding/SAML1ArtifactEncoder.h \
+       saml1/binding/SAML1POSTEncoder.h \
        saml1/binding/SAMLArtifactType0001.h \
        saml1/binding/SAMLArtifactType0002.h
 
@@ -80,11 +84,14 @@ noinst_HEADERS = \
 
 libsaml_la_SOURCES = \
        SAMLConfig.cpp \
+       binding/impl/ArtifactMap.cpp \
        binding/impl/SAMLArtifact.cpp \
        saml1/core/impl/AssertionsImpl.cpp \
        saml1/core/impl/AssertionsSchemaValidators.cpp \
        saml1/core/impl/ProtocolsImpl.cpp \
        saml1/core/impl/ProtocolsSchemaValidators.cpp \
+       saml1/binding/impl/SAML1ArtifactEncoder.cpp \
+       saml1/binding/impl/SAML1POSTEncoder.cpp \
        saml1/binding/impl/SAMLArtifactType0001.cpp \
        saml1/binding/impl/SAMLArtifactType0002.cpp \
        saml2/core/impl/Assertions20Impl.cpp \
index 80a49e1..3d40148 100644 (file)
@@ -24,6 +24,7 @@
 #include "internal.h"
 #include "exceptions.h"
 #include "SAMLConfig.h"
+#include "binding/MessageEncoder.h"
 #include "binding/SAMLArtifact.h"
 #include "saml1/core/Assertions.h"
 #include "saml1/core/Protocols.h"
@@ -65,6 +66,7 @@ extern "C" void SAML_API xmltooling_extension_term()
 
 DECL_EXCEPTION_FACTORY(ArtifactException,opensaml);
 DECL_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
+DECL_EXCEPTION_FACTORY(BindingException,opensaml);
 
 namespace opensaml {
    SAMLInternalConfig g_config;
@@ -95,7 +97,9 @@ bool SAMLInternalConfig::init(bool initXMLTooling)
 
     REGISTER_EXCEPTION_FACTORY(ArtifactException,opensaml);
     REGISTER_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
+    REGISTER_EXCEPTION_FACTORY(BindingException,opensaml);
 
+    registerMessageEncoders();
     registerSAMLArtifacts();
     saml1::registerAssertionClasses();
     saml1p::registerProtocolClasses();
@@ -122,10 +126,14 @@ void SAMLInternalConfig::term(bool termXMLTooling)
     saml2::AssertionSchemaValidators.destroyValidators();
     saml2md::MetadataSchemaValidators.destroyValidators();
     
-    SAMLArtifactManager.deregisterFactories();
+    TrustEngineManager.deregisterFactories();
     MetadataFilterManager.deregisterFactories();
     MetadataProviderManager.deregisterFactories();
-    TrustEngineManager.deregisterFactories();
+    SAMLArtifactManager.deregisterFactories();
+    MessageEncoderManager.deregisterFactories();
+
+    delete m_artifactMap;
+    m_artifactMap = NULL;
 
     if (termXMLTooling) {
         XMLToolingConfig::getConfig().term();
index 0474707..90e00ad 100644 (file)
@@ -24,6 +24,7 @@
 #define __saml_config_h__\r
 \r
 #include <saml/base.h>\r
+#include <saml/binding/ArtifactMap.h>\r
 \r
 #include <xmltooling/PluginManager.h>\r
 #include <xmltooling/XMLToolingConfig.h>\r
@@ -36,6 +37,8 @@
  */\r
 namespace opensaml {\r
 \r
+    class SAML_API MessageEncoder;\r
+    class SAML_API MessageDecoder;\r
     class SAML_API SAMLArtifact;\r
     class SAML_API TrustEngine;\r
 \r
@@ -91,6 +94,27 @@ namespace opensaml {
         virtual void term(bool termXMLTooling=true)=0;\r
         \r
         /**\r
+         * Sets the global ArtifactMap instance.\r
+         * This method must be externally synchronized with any code that uses the object.\r
+         * Any previously set object is destroyed.\r
+         * \r
+         * @param artifactMap   new ArtifactMap instance to store\r
+         */\r
+        void setArtifactMap(ArtifactMap* artifactMap) {\r
+            delete m_artifactMap;\r
+            m_artifactMap = artifactMap;\r
+        }\r
+        \r
+        /**\r
+         * Returns the global ArtifactMap instance.\r
+         * \r
+         * @return  global ArtifactMap\r
+         */\r
+        ArtifactMap* getArtifactMap() const {\r
+            return m_artifactMap;\r
+        }\r
+        \r
+        /**\r
          * Generate random information using the underlying security library\r
          * \r
          * @param buf   buffer for the information\r
@@ -123,16 +147,16 @@ namespace opensaml {
          * @return  SHA-1 hash of the data\r
          */\r
         virtual std::string hashSHA1(const char* s, bool toHex=false)=0;\r
-        \r
+\r
         /**\r
-         * Manages factories for MetadataProvider plugins.\r
+         * Manages factories for MessageDecoder plugins.\r
          */\r
-        xmltooling::PluginManager<saml2md::MetadataProvider,const DOMElement*> MetadataProviderManager;\r
-        \r
+        xmltooling::PluginManager<MessageDecoder,const DOMElement*> MessageDecoderManager;\r
+\r
         /**\r
-         * Manages factories for MetadataFilter plugins.\r
+         * Manages factories for MessageEncoder plugins.\r
          */\r
-        xmltooling::PluginManager<saml2md::MetadataFilter,const DOMElement*> MetadataFilterManager;\r
+        xmltooling::PluginManager<MessageEncoder,const DOMElement*> MessageEncoderManager;        \r
 \r
         /**\r
          * Manages factories for SAMLArtifact plugins.\r
@@ -144,8 +168,21 @@ namespace opensaml {
          */\r
         xmltooling::PluginManager<TrustEngine,const DOMElement*> TrustEngineManager;\r
 \r
+        /**\r
+         * Manages factories for MetadataProvider plugins.\r
+         */\r
+        xmltooling::PluginManager<saml2md::MetadataProvider,const DOMElement*> MetadataProviderManager;\r
+        \r
+        /**\r
+         * Manages factories for MetadataFilter plugins.\r
+         */\r
+        xmltooling::PluginManager<saml2md::MetadataFilter,const DOMElement*> MetadataFilterManager;\r
+\r
     protected:\r
-        SAMLConfig() {}\r
+        SAMLConfig() : m_artifactMap(NULL) {}\r
+        \r
+        /** Global ArtifactMap instance for use by artifact-related functions. */\r
+        ArtifactMap* m_artifactMap;\r
     };\r
 \r
 #if defined (_MSC_VER)\r
diff --git a/saml/binding/ArtifactMap.h b/saml/binding/ArtifactMap.h
new file mode 100644 (file)
index 0000000..7f57f88
--- /dev/null
@@ -0,0 +1,88 @@
+/*\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 saml/binding/ArtifactMap.h\r
+ * \r
+ * Helper class for SAMLArtifact mapping and retrieval.\r
+ */\r
+\r
+#ifndef __saml_artmap_h__\r
+#define __saml_artmap_h__\r
+\r
+#include <saml/base.h>\r
+#include <xmltooling/XMLObject.h>\r
+#include <xmltooling/util/StorageService.h>\r
+#include <xmltooling/util/Threads.h>\r
+\r
+namespace opensaml {\r
+\r
+    class SAML_API SAMLArtifact;\r
+    class SAML_DLLLOCAL ArtifactMappings;\r
+    \r
+    /**\r
+     * Helper class for SAMLArtifact mapping and retrieval.\r
+     */\r
+    class SAML_API ArtifactMap\r
+    {\r
+        MAKE_NONCOPYABLE(ArtifactMap);\r
+    public:\r
+        \r
+        /**\r
+         * Creates a map on top of a particular storage service context, or in-memory.\r
+         * \r
+         * @param storage       pointer to a StorageService, or NULL to keep map in memory\r
+         * @param context       optional label for storage context\r
+         * @param artifactTTL   time to live value, determines how long artifact remains valid\r
+         */\r
+        ArtifactMap(xmltooling::StorageService* storage=NULL, const char* context=NULL, int artifactTTL=180);\r
+\r
+        virtual ~ArtifactMap();\r
+        \r
+        /**\r
+         * Associates XML content with an artifact and optionally a specific relying party.\r
+         * Specifying no relying party means that the first attempt to resolve the artifact\r
+         * will succeed. The XML content cannot have a parent object, and any existing references\r
+         * to the content will be invalidated.\r
+         * \r
+         * @param content       the XML content to map to an artifact\r
+         * @param artifact      the artifact representing the XML content\r
+         * @param relyingParty  entityID of the party authorized to resolve the artifact\r
+         * @return the generated artifact\r
+         */\r
+        virtual void storeContent(xmltooling::XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty=NULL);\r
+        \r
+        /**\r
+         * Retrieves the XML content represented by the artifact. The identity of the\r
+         * relying party can be supplied, if known. If the wrong party tries to resolve\r
+         * an artifact, an exception will be thrown and the mapping will be removed.\r
+         * The caller is responsible for freeing the XML content returned.\r
+         * \r
+         * @param artifact      the artifact representing the XML content\r
+         * @param relyingParty  entityID of the party trying to resolve the artifact\r
+         * @return the XML content\r
+         */\r
+        virtual xmltooling::XMLObject* retrieveContent(const SAMLArtifact* artifact, const char* relyingParty=NULL);\r
+\r
+    private:\r
+        xmltooling::StorageService* m_storage;\r
+        std::string m_context;\r
+        ArtifactMappings* m_mappings;\r
+        int m_artifactTTL;\r
+    };\r
+};\r
+\r
+#endif /* __saml_artmap_h__ */\r
diff --git a/saml/binding/MessageEncoder.h b/saml/binding/MessageEncoder.h
new file mode 100644 (file)
index 0000000..4213bf3
--- /dev/null
@@ -0,0 +1,186 @@
+/*\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 saml/binding/MessageEncoder.h\r
+ * \r
+ * Interface to SAML protocol binding message encoders. \r
+ */\r
+\r
+#ifndef __saml_encoder_h__\r
+#define __saml_encoder_h__\r
+\r
+#include <saml/base.h>\r
+\r
+#include <map>\r
+#include <string>\r
+#include <xmltooling/XMLObject.h>\r
+#include <xmltooling/signature/CredentialResolver.h>\r
+#include <xmltooling/util/StorageService.h>\r
+\r
+namespace opensaml {\r
+\r
+    class SAML_API SAMLArtifact;\r
+    namespace saml2p {\r
+        class SAML_API SAML2Artifact;\r
+    };\r
+\r
+    /**\r
+     * Interface to SAML protocol binding message encoders.\r
+     */\r
+    class SAML_API MessageEncoder\r
+    {\r
+        MAKE_NONCOPYABLE(MessageEncoder);\r
+    public:\r
+        virtual ~MessageEncoder() {}\r
+\r
+        /**\r
+         * Interface to caller-supplied URL-encoding mechanism.\r
+         * \r
+         * Since URL-encoding is not canonical, it's important that the same\r
+         * encoder is used during some binding-specific signature operations.\r
+         */\r
+        class SAML_API URLEncoder {\r
+            MAKE_NONCOPYABLE(URLEncoder);\r
+        protected:\r
+            URLEncoder() {}\r
+        public:\r
+            virtual ~URLEncoder() {}\r
+            \r
+            /**\r
+             * Produce a URL-safe but equivalent version of the input string.\r
+             * \r
+             * @param s input string to encode\r
+             * @return a string object containing the result of encoding the input\r
+             */\r
+            virtual std::string encode(const char* s) const=0;\r
+        };\r
+        \r
+        /**\r
+         * Provides a URLEncoder implementation for the MessageEncoder to use.\r
+         * The implementation's lifetime must be longer than the lifetime of this object.\r
+         * This method must be externally synchronized. \r
+         * \r
+         * @param urlEncoder    a URLEncoder implementation to use\r
+         */\r
+        void setURLEncoder(const URLEncoder* urlEncoder) {\r
+            m_urlEncoder = urlEncoder;\r
+        }\r
+\r
+        /**\r
+         * Interface to caller-supplied artifact generation mechanism.\r
+         * \r
+         * Generating an artifact for storage and retrieval requires knowledge of\r
+         * the sender's SourceID (or sometimes SourceLocation), and the relying party's\r
+         * preferred artifact type. This information can be supplied using whatever\r
+         * configuration or defaults are appropriate for the SAML application.\r
+         * An ArtifactMap implementation will invoke the supplied generator interface\r
+         * when it requires an artifact be created.\r
+         */\r
+        class SAML_API ArtifactGenerator {\r
+            MAKE_NONCOPYABLE(ArtifactGenerator);\r
+        protected:\r
+            ArtifactGenerator() {}\r
+        public:\r
+            virtual ~ArtifactGenerator() {}\r
+            \r
+            /**\r
+             * Generate a SAML 1.x artifact suitable for consumption by the relying party.\r
+             * \r
+             * @param relyingParty  the party that will recieve the artifact\r
+             * @return a SAML 1.x artifact with a random assertion handle\r
+             */\r
+            virtual SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const=0;\r
+\r
+            /**\r
+             * Generate a SAML 2.0 artifact suitable for consumption by the relying party.\r
+             * \r
+             * @param relyingParty  the party that will recieve the artifact\r
+             * @return a SAML 2.0 artifact with a random message handle\r
+             */\r
+            virtual saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const=0;\r
+        };\r
+\r
+        /**\r
+         * Provides an ArtifactGenerator implementation for the MessageEncoder to use.\r
+         * The implementation's lifetime must be longer than the lifetime of this object. \r
+         * This method must be externally synchronized. \r
+         * \r
+         * @param artifactGenerator   an ArtifactGenerator implementation to use\r
+         */\r
+        void setArtifactGenerator(ArtifactGenerator* artifactGenerator) {\r
+            m_artifactGenerator = artifactGenerator;\r
+        }\r
+        \r
+        /**\r
+         * Encodes an XML object/message into a set of binding-specific data "fields".\r
+         * The XML content cannot have a parent object, and any existing references to\r
+         * the content will be invalidated if the encode method returns successfully.\r
+         * \r
+         * If a CredentialResolver is supplied, the message is also signed in a\r
+         * binding-specific manner. The CredentialResolver <strong>MUST</strong>\r
+         * be locked by the caller. \r
+         * \r
+         * <p>An embedded URLEncoder instance may be required by some bindings\r
+         * in order to produce predictable signature input.\r
+         * \r
+         * <p>Artifact-based bindings require an ArtifactGenerator be set to\r
+         * produce an artifact suitable for the intended recipient.\r
+         * \r
+         * <p>Note that the name/value pairs resulting from the encoding operation are\r
+         * <strong>NOT</strong> URL-encoded or otherwise transformed. It is the caller's\r
+         * responsibility to apply any necessary encoding when preparing the data for\r
+         * transport.\r
+         * \r
+         * @param outputFields      name/value pairs containing the results of encoding the message\r
+         * @param xmlObject         XML object/message to encode\r
+         * @param recipientID       optional entityID of message recipient\r
+         * @param relayState        optional RelayState value to accompany message\r
+         * @param credResolver      optional CredentialResolver instance to supply signing material\r
+         * @param sigAlgorithm      optional signature algorithm identifier\r
+         */\r
+        virtual void encode(\r
+            std::map<std::string,std::string>& outputFields,\r
+            xmltooling::XMLObject* xmlObject,\r
+            const char* recipientID=NULL,\r
+            const char* relayState=NULL,\r
+            const xmlsignature::CredentialResolver* credResolver=NULL,\r
+            const XMLCh* sigAlgorithm=NULL\r
+            ) const=0;\r
+\r
+    protected:\r
+        MessageEncoder() : m_urlEncoder(NULL), m_artifactGenerator(NULL) {}\r
+        \r
+        /** Pointer to a URLEncoder implementation. */\r
+        const URLEncoder* m_urlEncoder;\r
+        \r
+        /** Pointer to an ArtifactGenerator implementation. */\r
+        const ArtifactGenerator* m_artifactGenerator;\r
+    };\r
+\r
+    /**\r
+     * Registers MessageEncoder plugins into the runtime.\r
+     */\r
+    void SAML_API registerMessageEncoders();\r
+\r
+    /** MessageEncoder for SAML 1.x Browser/Artifact "binding" (really part of profile) */\r
+    #define SAML1_ARTIFACT_ENCODER  "org.opensaml.saml1.binding.SAML1ArtifactEncoder"\r
+\r
+    /** MessageEncoder for SAML 1.x Browser/POST "binding" (really part of profile) */\r
+    #define SAML1_POST_ENCODER  "org.opensaml.saml1.binding.SAML1POSTEncoder"\r
+};\r
+\r
+#endif /* __saml_encoder_h__ */\r
diff --git a/saml/binding/impl/ArtifactMap.cpp b/saml/binding/impl/ArtifactMap.cpp
new file mode 100644 (file)
index 0000000..6866c6b
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * ArtifactMap.cpp
+ * 
+ * Helper class for SAMLArtifact mapping and retrieval. 
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/ArtifactMap.h"
+#include "binding/SAMLArtifact.h"
+
+#include <log4cpp/Category.hh>
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/XMLObjectBuilder.h>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    // In-memory storage of mappings instead of using storage API.
+    class SAML_DLLLOCAL ArtifactMappings
+    {
+    public:
+        ArtifactMappings() : m_lock(Mutex::create()) {}
+        ~ArtifactMappings() {
+            delete m_lock;
+            for (map<string,Mapping>::iterator i=m_artMap.begin(); i!=m_artMap.end(); ++i)
+                delete i->second.m_xml;
+        }
+        void storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty, int TTL);
+        XMLObject* retrieveContent(const SAMLArtifact* artifact, const char* relyingParty);
+    
+    private:
+        struct SAML_DLLLOCAL Mapping {
+            Mapping() : m_xml(NULL), m_expires(0) {}
+            XMLObject* m_xml;
+            string m_relying;
+            time_t m_expires;
+        };
+
+        void removeMapping(const map<string,Mapping>::iterator& i);
+        
+        Mutex* m_lock;
+        map<string,Mapping> m_artMap;
+        multimap<time_t,string> m_expMap;
+    };
+};
+
+void ArtifactMappings::removeMapping(const map<string,Mapping>::iterator& i)
+{
+    // Update secondary map.
+    pair<multimap<time_t,string>::iterator,multimap<time_t,string>::iterator> range =
+        m_expMap.equal_range(i->second.m_expires);
+    for (; range.first != range.second; ++range.first) {
+        if (range.first->second == i->first) {
+            m_expMap.erase(range.first);
+            break;
+        }
+    }
+    delete i->second.m_xml;
+    m_artMap.erase(i);
+}
+
+void ArtifactMappings::storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty, int TTL)
+{
+    Lock wrapper(m_lock);
+
+    // Garbage collect any expired artifacts.
+    time_t now=time(NULL);
+    multimap<time_t,string>::iterator stop=m_expMap.upper_bound(now);
+    for (multimap<time_t,string>::iterator i=m_expMap.begin(); i!=stop; m_expMap.erase(i++)) {
+        delete m_artMap[i->second].m_xml;
+        m_artMap.erase(i->second);
+    }
+    
+    // Key is the hexed handle.
+    string hexed = SAMLArtifact::toHex(artifact->getMessageHandle());
+    Mapping& m = m_artMap[hexed];
+    m.m_xml = content;
+    if (relyingParty)
+        m.m_relying = relyingParty;
+    m.m_expires = now + TTL;
+    m_expMap.insert(make_pair(m.m_expires,hexed));
+}
+
+XMLObject* ArtifactMappings::retrieveContent(const SAMLArtifact* artifact, const char* relyingParty)
+{
+    Category& log=Category::getInstance(SAML_LOGCAT".ArtifactMap");
+    Lock wrapper(m_lock);
+
+    map<string,Mapping>::iterator i=m_artMap.find(SAMLArtifact::toHex(artifact->getMessageHandle()));
+    if (i==m_artMap.end())
+        throw BindingException("Requested artifact not in map or may have expired.");
+    
+    if (!(i->second.m_relying.empty())) {
+        if (!relyingParty || i->second.m_relying != relyingParty) {
+            log.warn(
+                "request from (%s) for artifact issued to (%s)",
+                relyingParty ? relyingParty : "unknown", i->second.m_relying.c_str()
+                );
+            removeMapping(i);
+            throw BindingException("Unauthorized artifact mapping request.");
+        }
+    }
+    
+    if (time(NULL) >= i->second.m_expires) {
+        removeMapping(i);
+        throw BindingException("Requested artifact has expired.");
+    }
+    
+    log.debug("resolved artifact for (%s)", relyingParty ? relyingParty : "unknown");
+    XMLObject* ret = i->second.m_xml;
+    i->second.m_xml = NULL; // clear member so it doesn't get deleted
+    removeMapping(i);
+    return ret;
+}
+
+ArtifactMap::ArtifactMap(xmltooling::StorageService* storage, const char* context, int artifactTTL)
+    : m_storage(storage), m_context(context ? context : "opensaml::ArtifactMap"), m_mappings(NULL), m_artifactTTL(artifactTTL)
+{
+    if (!m_storage)
+        m_mappings = new ArtifactMappings();
+}
+
+ArtifactMap::~ArtifactMap()
+{
+    delete m_mappings;
+}
+
+static const XMLCh M[] = UNICODE_LITERAL_7(M,a,p,p,i,n,g);
+static const XMLCh RP[] = UNICODE_LITERAL_12(r,e,l,y,i,n,g,P,a,r,t,y);
+
+void ArtifactMap::storeContent(XMLObject* content, const SAMLArtifact* artifact, const char* relyingParty)
+{
+    if (content->getParent())
+        throw BindingException("Cannot store artifact mapping for XML content with parent.");
+    else if (!m_storage)
+        return m_mappings->storeContent(content, artifact, relyingParty, m_artifactTTL);
+    
+    // Marshall with defaulted document, to reuse existing DOM and/or create a bound Document.
+    DOMElement* root = content->marshall();
+    
+    // Build a DOM with the same document to store the relyingParty mapping.
+    if (relyingParty) {
+        auto_ptr_XMLCh temp(relyingParty);
+        root = root->getOwnerDocument()->createElementNS(NULL,M);
+        root->setAttributeNS(NULL,RP,temp.get());
+        root->appendChild(content->getDOM());
+    }
+    
+    // Serialize the root element, whatever it is, for storage.
+    string xmlbuf;
+    XMLHelper::serialize(root, xmlbuf);
+    m_storage->createText(
+        m_context.c_str(), SAMLArtifact::toHex(artifact->getMessageHandle()).c_str(), xmlbuf.c_str(), time(NULL) + m_artifactTTL
+        );
+        
+    // Cleanup by destroying XML.
+    delete content;
+}
+
+XMLObject* ArtifactMap::retrieveContent(const SAMLArtifact* artifact, const char* relyingParty)
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("retrieveContent");
+#endif
+
+    if (!m_storage)
+        return m_mappings->retrieveContent(artifact, relyingParty);
+    
+    string xmlbuf;
+    string key = SAMLArtifact::toHex(artifact->getMessageHandle());
+    if (!m_storage->readText(m_context.c_str(), key.c_str(), &xmlbuf))
+        throw BindingException("Artifact not found in mapping database.");
+    
+    istringstream is(xmlbuf);
+    DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(is);
+    XercesJanitor<DOMDocument> janitor(doc);
+
+    Category& log=Category::getInstance(SAML_LOGCAT".ArtifactMap");
+    m_storage->deleteText(m_context.c_str(), key.c_str());
+    
+    // Check the root element.
+    DOMElement* messageRoot = doc->getDocumentElement();
+    if (XMLHelper::isNodeNamed(messageRoot, NULL, M)) {
+        auto_ptr_char temp(messageRoot->getAttributeNS(NULL,RP));
+        if (!relyingParty || strcmp(temp.get(),relyingParty)) {
+            log.warn("request from (%s) for artifact issued to (%s)", relyingParty ? relyingParty : "unknown", temp.get());
+            throw BindingException("Unauthorized artifact mapping request.");
+        }
+        messageRoot = XMLHelper::getFirstChildElement(messageRoot);
+    }
+    
+    // Unmarshall...
+    XMLObject* xmlObject = XMLObjectBuilder::buildOneFromElement(messageRoot, true);    // bind document
+    janitor.release();
+    
+    log.debug("resolved artifact for (%s)", relyingParty ? relyingParty : "unknown");
+    return xmlObject;
+}
diff --git a/saml/binding/impl/MessageEncoder.cpp b/saml/binding/impl/MessageEncoder.cpp
new file mode 100644 (file)
index 0000000..7510254
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * MessageEncoder.cpp
+ * 
+ * Interface to SAML protocol binding message encoders. 
+ */
+
+#include "internal.h"
+#include "binding/MessageEncoder.h"
+
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+    namespace saml1p {
+        SAML_DLLLOCAL PluginManager<MessageEncoder,const DOMElement*>::Factory SAML1ArtifactEncoderFactory;
+        SAML_DLLLOCAL PluginManager<MessageEncoder,const DOMElement*>::Factory SAML1POSTEncoderFactory;
+    }; 
+};
+
+void SAML_API opensaml::registerMessageEncoders()
+{
+    SAMLConfig& conf=SAMLConfig::getConfig();
+    conf.MessageEncoderManager.registerFactory(SAML1_ARTIFACT_ENCODER, saml1p::SAML1ArtifactEncoderFactory);
+    conf.MessageEncoderManager.registerFactory(SAML1_POST_ENCODER, saml1p::SAML1POSTEncoderFactory);
+}
index 700991a..186aa4e 100644 (file)
@@ -27,7 +27,7 @@
 #include <xmltooling/exceptions.h>
 
 namespace opensaml {
-    
+    DECL_XMLTOOLING_EXCEPTION(BindingException,SAML_EXCEPTIONAPI(SAML_API),opensaml,xmltooling::XMLToolingException,Exceptions in SAML binding processing);
 };
 
 #endif /* __saml_exceptions_h__ */
index 7db28ff..1c47f4e 100644 (file)
                                                Name="impl"\r
                                                >\r
                                                <File\r
+                                                       RelativePath=".\saml1\binding\impl\SAML1ArtifactEncoder.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml1\binding\impl\SAML1POSTEncoder.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml1\binding\impl\SAMLArtifactType0001.cpp"\r
                                                        >\r
                                                </File>\r
                                        Name="impl"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\binding\impl\ArtifactMap.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
+                                               RelativePath=".\binding\impl\MessageEncoder.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\binding\impl\SAMLArtifact.cpp"\r
                                                >\r
                                        </File>\r
                                        Name="binding"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1ArtifactEncoder.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
+                                               RelativePath=".\saml1\binding\SAML1POSTEncoder.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml1\binding\SAMLArtifactType0001.h"\r
                                                >\r
                                        </File>\r
                                Name="binding"\r
                                >\r
                                <File\r
+                                       RelativePath=".\binding\ArtifactMap.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\binding\MessageEncoder.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\binding\SAMLArtifact.h"\r
                                        >\r
                                </File>\r
diff --git a/saml/saml1/binding/SAML1ArtifactEncoder.h b/saml/saml1/binding/SAML1ArtifactEncoder.h
new file mode 100644 (file)
index 0000000..3bd1cdd
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * @file saml/saml1/binding/SAML1ArtifactEncoder.h
+ * 
+ * SAML 1.x Artifact binding/profile message encoder
+ */
+
+#include <saml/binding/MessageEncoder.h>
+
+
+namespace opensaml {
+    namespace saml1p {
+
+        /**
+         * SAML 1.x Artifact binding/profile message encoder
+         */
+        class SAML_API SAML1ArtifactEncoder : public MessageEncoder
+        {
+        public:
+            SAML1ArtifactEncoder(const DOMElement* e);
+            virtual ~SAML1ArtifactEncoder();
+            
+            void encode(
+                std::map<std::string,std::string>& outputFields,
+                xmltooling::XMLObject* xmlObject,
+                const char* recipientID=NULL,
+                const char* relayState=NULL,
+                const xmlsignature::CredentialResolver* credResolver=NULL,
+                const XMLCh* sigAlgorithm=NULL
+                ) const;
+        };                
+
+    };
+};
diff --git a/saml/saml1/binding/SAML1POSTEncoder.h b/saml/saml1/binding/SAML1POSTEncoder.h
new file mode 100644 (file)
index 0000000..c99c38d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * @file saml/saml1/binding/SAML1POSTEncoder.h
+ * 
+ * SAML 1.x POST binding/profile message encoder
+ */
+
+#include <saml/binding/MessageEncoder.h>
+
+
+namespace opensaml {
+    namespace saml1p {
+
+        /**
+         * SAML 1.x POST binding/profile message encoder
+         */
+        class SAML_API SAML1POSTEncoder : public MessageEncoder
+        {
+        public:
+            SAML1POSTEncoder(const DOMElement* e);
+            virtual ~SAML1POSTEncoder();
+            
+            void encode(
+                std::map<std::string,std::string>& outputFields,
+                xmltooling::XMLObject* xmlObject,
+                const char* recipientID=NULL,
+                const char* relayState=NULL,
+                const xmlsignature::CredentialResolver* credResolver=NULL,
+                const XMLCh* sigAlgorithm=NULL
+                ) const;
+        };                
+
+    };
+};
diff --git a/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp
new file mode 100644 (file)
index 0000000..197ecb4
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * SAML1ArtifactEncoder.cpp
+ * 
+ * SAML 1.x Artifact binding/profile message encoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml/binding/SAMLArtifact.h"
+#include "saml1/binding/SAML1ArtifactEncoder.h"
+#include "saml1/core/Assertions.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml1;
+using namespace opensaml::saml1p;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml1p {              
+        MessageEncoder* SAML_DLLLOCAL SAML1ArtifactEncoderFactory(const DOMElement* const & e)
+        {
+            return new SAML1ArtifactEncoder(e);
+        }
+    };
+};
+
+SAML1ArtifactEncoder::SAML1ArtifactEncoder(const DOMElement* e) {}
+
+SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {}
+
+void SAML1ArtifactEncoder::encode(
+    map<string,string>& outputFields,
+    XMLObject* xmlObject,
+    const char* recipientID,
+    const char* relayState,
+    const CredentialResolver* credResolver,
+    const XMLCh* sigAlgorithm
+    ) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("encode");
+#endif
+    Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1Artifact");
+    log.debug("validating input");
+    
+    outputFields.clear();
+    if (xmlObject->getParent())
+        throw BindingException("Cannot encode XML content with parent.");
+    Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);
+    if (!assertion)
+        throw BindingException("XML content for SAML 1.x Artifact Encoder must be a SAML 1.x <Assertion>.");
+    if (!relayState)
+        throw BindingException("SAML 1.x Artifact Encoder requires relay state (TARGET) value.");
+    
+    // Signing is a protocol level issue, so no signing here...
+    
+    ArtifactMap* mapper = SAMLConfig::getConfig().getArtifactMap();
+    if (!mapper)
+        throw BindingException("SAML 1.x Artifact Encoder requires ArtifactMap be set in configuration.");
+
+    // Obtain a fresh artifact.
+    if (!m_artifactGenerator)
+        throw BindingException("SAML 1.x Artifact Encoder requires an ArtifactGenerator instance.");
+    log.debug("obtaining new artifact for relying party (%s)", recipientID ? recipientID : "unknown");
+    auto_ptr<SAMLArtifact> artifact(m_artifactGenerator->generateSAML1Artifact(recipientID));
+    
+    // Pass back output fields.
+    outputFields["SAMLart"] = artifact->encode();
+    outputFields["TARGET"] = relayState;
+
+    // Store the assertion. Last step in storage will be to delete the XML.
+    log.debug("storing artifact and content in map");
+    mapper->storeContent(xmlObject, artifact.get(), recipientID);
+
+    log.debug("message encoded");
+}
diff --git a/saml/saml1/binding/impl/SAML1POSTEncoder.cpp b/saml/saml1/binding/impl/SAML1POSTEncoder.cpp
new file mode 100644 (file)
index 0000000..f62bd62
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  Copyright 2001-2006 Internet2
+ * 
+ * Licensed 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.
+ */
+
+/**
+ * SAML1POSTEncoder.cpp
+ * 
+ * SAML 1.x Artifact binding/profile message encoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml1/binding/SAML1POSTEncoder.h"
+#include "saml1/core/Protocols.h"
+
+#include <log4cpp/Category.hh>
+#include <xercesc/util/Base64.hpp>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml1p;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml1p {              
+        MessageEncoder* SAML_DLLLOCAL SAML1POSTEncoderFactory(const DOMElement* const & e)
+        {
+            return new SAML1POSTEncoder(e);
+        }
+
+        class SAML_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {
+        public:
+            void operator()(X509Data* bag, XSECCryptoX509* cert) const {
+                safeBuffer& buf=cert->getDEREncodingSB();
+                X509Certificate* x=X509CertificateBuilder::buildX509Certificate();
+                x->setValue(buf.sbStrToXMLCh());
+                bag->getX509Certificates().push_back(x);
+            }
+        };
+    };
+};
+
+SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e) {}
+
+SAML1POSTEncoder::~SAML1POSTEncoder() {}
+
+void SAML1POSTEncoder::encode(
+    map<string,string>& outputFields,
+    XMLObject* xmlObject,
+    const char* recipientID,
+    const char* relayState,
+    const CredentialResolver* credResolver,
+    const XMLCh* sigAlgorithm
+    ) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("encode");
+#endif
+    Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST");
+    log.debug("validating input");
+    
+    outputFields.clear();
+    if (xmlObject->getParent())
+        throw BindingException("Cannot encode XML content with parent.");
+    Response* response = dynamic_cast<Response*>(xmlObject);
+    if (!response)
+        throw BindingException("XML content for SAML 1.x POST Encoder must be a SAML 1.x <Response>.");
+    if (!relayState)
+        throw BindingException("SAML 1.x POST Encoder requires relay state (TARGET) value.");
+    
+    DOMElement* rootElement = NULL;
+    if (credResolver) {
+        // Signature based on native XML signing.
+        if (response->getSignature()) {
+            log.debug("response already signed, skipping signature operation");
+        }
+        else {
+            log.debug("signing and marshalling the response");
+
+            // Append a Signature.
+            response->setSignature(SignatureBuilder::buildSignature());
+            response->getSignature()->setSigningKey(credResolver->getKey());
+    
+            // Build KeyInfo.
+            const vector<XSECCryptoX509*>& certs = credResolver->getCertificates();
+            if (!certs.empty()) {
+                KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();
+                X509Data* x509Data=X509DataBuilder::buildX509Data();
+                keyInfo->getX509Datas().push_back(x509Data);
+                for_each(certs.begin(),certs.end(),bind1st(_addcert(),x509Data));
+                response->getSignature()->setKeyInfo(keyInfo);
+            }
+    
+            // Sign response while marshalling.
+            vector<Signature*> sigs(1,response->getSignature());
+            rootElement = response->marshall((DOMDocument*)NULL,&sigs);
+        }
+    }
+    else {
+        log.debug("marshalling the response");
+        rootElement = response->marshall();
+    }
+    
+    string xmlbuf;
+    XMLHelper::serialize(rootElement, xmlbuf);
+    unsigned int len=0;
+    XMLByte* out=Base64::encode(reinterpret_cast<const XMLByte*>(xmlbuf.data()),xmlbuf.size(),&len);
+    if (out) {
+        xmlbuf.erase();
+        xmlbuf.append(reinterpret_cast<char*>(out),len);
+        XMLString::release(&out);
+    }
+    else {
+        throw BindingException("Base64 encoding of XML failed.");
+    }
+    
+    // Pass back output fields.
+    outputFields["SAMLResponse"] = xmlbuf;
+    outputFields["TARGET"] = relayState;
+
+    // Cleanup by destroying XML.
+    delete xmlObject;
+
+    log.debug("message encoded");
+}
index a008992..465fd04 100644 (file)
@@ -15,9 +15,9 @@
  */
 
 /**
- * BlacklistMetadataFilter.cpp
+ * SignatureMetadataFilter.cpp
  * 
- * Removes blacklisted entities from a metadata instance
+ * Filters out unsigned or mis-signed elements.
  */
 
 #include "internal.h"
diff --git a/samltest/ArtifactMapTest.h b/samltest/ArtifactMapTest.h
new file mode 100644 (file)
index 0000000..72a8b2d
--- /dev/null
@@ -0,0 +1,55 @@
+/*\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 "internal.h"\r
+#include <saml/SAMLConfig.h>\r
+#include <saml/saml2/binding/SAML2ArtifactType0004.h>\r
+#include <saml/saml2/core/Protocols.h>\r
+\r
+using namespace opensaml::saml2p;\r
+using namespace opensaml;\r
+using namespace std;\r
+\r
+class ArtifactMapTest : public CxxTest::TestSuite\r
+{\r
+public:\r
+    string providerIdStr;\r
+    string handle;\r
+    ArtifactMap* artifactMap;\r
+    void setUp() {\r
+        if (handle.empty()) {\r
+            providerIdStr = "https://idp.org/SAML";\r
+            SAMLConfig::getConfig().generateRandomBytes(handle,SAML2ArtifactType0004::HANDLE_LENGTH);\r
+        }\r
+        artifactMap = new ArtifactMap();\r
+    }\r
+    void tearDown() {\r
+        delete artifactMap;\r
+        artifactMap=NULL;\r
+    }\r
+    void testArtifactMap(void) {\r
+        auto_ptr<Response> response(ResponseBuilder::buildResponse());\r
+\r
+        SAML2ArtifactType0004 artifact(SAMLConfig::getConfig().hashSHA1(providerIdStr.c_str()),666,handle);\r
+\r
+        artifactMap->storeContent(response.get(), &artifact, providerIdStr.c_str());\r
+        response.release();\r
+\r
+        auto_ptr<XMLObject> xmlObject(artifactMap->retrieveContent(&artifact, providerIdStr.c_str()));\r
+        TSM_ASSERT_THROWS("Artifact resolution improperly succeeded.", artifactMap->retrieveContent(&artifact), BindingException);\r
+        TSM_ASSERT("Mapped content was not a Response.", dynamic_cast<Response*>(xmlObject.get())!=NULL);\r
+    }\r
+};\r
index 8aab1f1..d81f080 100644 (file)
@@ -13,6 +13,7 @@ samltest_h = \
     SAMLArtifactType0001Test.h \
     SAMLArtifactType0002Test.h \
     SAMLArtifactType0004Test.h \
+    ArtifactMapTest.h \
     signature/SAML1AssertionTest.h \
     signature/SAML1RequestTest.h \
     signature/SAML1ResponseTest.h \
index 7264b35..cf9102d 100644 (file)
                        UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
                        >\r
                        <File\r
+                               RelativePath=".\ArtifactMapTest.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\SAMLArtifactCreationTest.cpp"\r
                                >\r
                        </File>\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
                        >\r
                        <File\r
+                               RelativePath=".\ArtifactMapTest.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;$(InputDir)$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputDir)$(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;$(InputDir)$(InputName)&quot;.cpp &quot;$(InputPath)&quot;"\r
+                                               Outputs="&quot;$(InputDir)$(InputName)&quot;.cpp"\r
+                                       />\r
+                               </FileConfiguration>\r
+                       </File>\r
+                       <File\r
                                RelativePath=".\internal.h"\r
                                >\r
                        </File>\r