1.x Artifact decoder, unit test.
authorScott Cantor <cantor.2@osu.edu>
Mon, 9 Oct 2006 04:15:00 +0000 (04:15 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 9 Oct 2006 04:15:00 +0000 (04:15 +0000)
14 files changed:
saml/binding/MessageDecoder.h
saml/binding/impl/MessageDecoder.cpp
saml/saml.vcproj
saml/saml1/binding/SAML1ArtifactDecoder.h [new file with mode: 0644]
saml/saml1/binding/SAML1POSTDecoder.h
saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp [new file with mode: 0644]
saml/saml1/binding/impl/SAML1POSTDecoder.cpp
saml/saml2/binding/SAML2POSTDecoder.h
saml/saml2/binding/impl/SAML2POSTDecoder.cpp
samltest/ArtifactMapTest.h
samltest/data/saml1/binding/SAML1Assertion.xml [new file with mode: 0644]
samltest/saml1/binding/SAML1ArtifactTest.h [new file with mode: 0644]
samltest/samltest.h
samltest/samltest.vcproj

index 609273f..0cfdbba 100644 (file)
@@ -127,20 +127,37 @@ namespace opensaml {
             MAKE_NONCOPYABLE(ArtifactResolver);\r
         protected:\r
             ArtifactResolver() {}\r
+            \r
+            /** Flag controlling schema validation. */\r
+            bool m_validate;\r
+\r
         public:\r
             virtual ~ArtifactResolver() {}\r
+\r
+            /**\r
+             * Controls schema validation of incoming XML messages.\r
+             * This is separate from other forms of programmatic validation of objects,\r
+             * but can detect a much wider range of syntax errors. \r
+             * \r
+             * @param validate  true iff the resolver should use a validating XML parser\r
+             */\r
+            void setValidating(bool validate=true) {\r
+                m_validate = validate;\r
+            }\r
             \r
             /**\r
              * Resolves one or more SAML 1.x artifacts into a response containing a set of\r
              * resolved Assertions. The caller is responsible for the resulting Response. \r
              * \r
+             * @param authenticated     output flag set to true iff the resolution channel was authenticated\r
              * @param artifacts         one or more SAML 1.x artifacts\r
              * @param idpDescriptor     reference to IdP role of artifact issuer\r
              * @param trustEngine       optional pointer to X509TrustEngine supplied to MessageDecoder\r
              * @return the corresponding SAML Assertions wrapped in a Response.\r
              */\r
             virtual saml1p::Response* resolve(\r
-                const std::vector<const SAMLArtifact*>& artifacts,\r
+                bool& authenticated,\r
+                const std::vector<SAMLArtifact*>& artifacts,\r
                 const saml2md::IDPSSODescriptor& idpDescriptor,\r
                 const X509TrustEngine* trustEngine=NULL\r
                 ) const=0;\r
@@ -149,12 +166,14 @@ namespace opensaml {
              * Resolves a SAML 2.0 artifact into the corresponding SAML protocol message.\r
              * The caller is responsible for the resulting XMLObject.\r
              * \r
+             * @param authenticated     output flag set to true iff the resolution channel was authenticated\r
              * @param artifact          reference to a SAML 2.0 artifact\r
              * @param ssoDescriptor     reference to SSO role of artifact issuer (may be SP or IdP)\r
              * @param trustEngine       optional pointer to X509TrustEngine supplied to MessageDecoder\r
              * @return the corresponding SAML protocol message or NULL\r
              */\r
             virtual xmltooling::XMLObject* resolve(\r
+                bool& authenticated,\r
                 const saml2p::SAML2Artifact& artifact,\r
                 const saml2md::SSODescriptorType& ssoDescriptor,\r
                 const X509TrustEngine* trustEngine=NULL\r
@@ -170,6 +189,8 @@ namespace opensaml {
          */\r
         void setArtifactResolver(ArtifactResolver* artifactResolver) {\r
             m_artifactResolver = artifactResolver;\r
+            if (m_artifactResolver)\r
+                m_artifactResolver->setValidating(m_validate);\r
         }\r
         \r
         /**\r
@@ -181,6 +202,8 @@ namespace opensaml {
          */\r
         void setValidating(bool validate=true) {\r
             m_validate = validate;\r
+            if (m_artifactResolver)\r
+                m_artifactResolver->setValidating(m_validate);\r
         }\r
 \r
         /**\r
@@ -198,11 +221,12 @@ namespace opensaml {
          * \r
          * @param relayState        RelayState/TARGET value accompanying message\r
          * @param issuer            role descriptor of issuing party\r
-         * @param issuerTrusted     will be true iff the message was authenticated (signed or obtained via secure backchannel)\r
+         * @param issuerTrusted     output flag set to true iff the message was authenticated\r
+         *                          (signed or obtained via secure backchannel)\r
          * @param httpRequest       reference to interface for accessing HTTP message to decode\r
          * @param metadataProvider  optional MetadataProvider instance to authenticate the message\r
          * @param role              optional, identifies the role (generally IdP or SP) of the peer who issued the message \r
-         * @param trustEngine       optional X509TrustEngine to authenticate the message\r
+         * @param trustEngine       optional TrustEngine to authenticate the message\r
          * @return  the decoded message, or NULL if the decoder did not recognize the request content\r
          */\r
         virtual xmltooling::XMLObject* decode(\r
@@ -212,14 +236,14 @@ namespace opensaml {
             const HTTPRequest& httpRequest,\r
             const saml2md::MetadataProvider* metadataProvider=NULL,\r
             const xmltooling::QName* role=NULL,\r
-            const X509TrustEngine* trustEngine=NULL\r
+            const TrustEngine* trustEngine=NULL\r
             ) const=0;\r
 \r
     protected:\r
         MessageDecoder() : m_artifactResolver(NULL), m_validate(false) {}\r
 \r
         /** Pointer to an ArtifactResolver implementation. */\r
-        const ArtifactResolver* m_artifactResolver;\r
+        ArtifactResolver* m_artifactResolver;\r
         \r
         /** Flag controlling schema validation. */\r
         bool m_validate;\r
index e867ddb..14a7d19 100644 (file)
@@ -41,7 +41,7 @@ namespace opensaml {
 void SAML_API opensaml::registerMessageDecoders()
 {
     SAMLConfig& conf=SAMLConfig::getConfig();
-    //conf.MessageDecoderManager.registerFactory(SAML1_ARTIFACT_DECODER, saml1p::SAML1ArtifactDecoderFactory);
+    conf.MessageDecoderManager.registerFactory(SAML1_ARTIFACT_DECODER, saml1p::SAML1ArtifactDecoderFactory);
     conf.MessageDecoderManager.registerFactory(SAML1_POST_DECODER, saml1p::SAML1POSTDecoderFactory);
     //conf.MessageDecoderManager.registerFactory(SAML2_ARTIFACT_DECODER, saml2p::SAML2ArtifactDecoderFactory);
     conf.MessageDecoderManager.registerFactory(SAML2_POST_DECODER, saml2p::SAML2POSTDecoderFactory);
index 135d2c9..1fe2f1c 100644 (file)
                                                Name="impl"\r
                                                >\r
                                                <File\r
+                                                       RelativePath=".\saml1\binding\impl\SAML1ArtifactDecoder.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml1\binding\impl\SAML1ArtifactEncoder.cpp"\r
                                                        >\r
                                                </File>\r
                                        Name="binding"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1ArtifactDecoder.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml1\binding\SAML1ArtifactEncoder.h"\r
                                                >\r
                                        </File>\r
diff --git a/saml/saml1/binding/SAML1ArtifactDecoder.h b/saml/saml1/binding/SAML1ArtifactDecoder.h
new file mode 100644 (file)
index 0000000..7e2da54
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  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/SAML1ArtifactDecoder.h
+ * 
+ * SAML 1.x Artifact binding/profile message decoder
+ */
+
+#include <saml/binding/MessageDecoder.h>
+#include <saml/saml1/core/Protocols.h>
+
+
+namespace opensaml {
+    namespace saml1p {
+
+        /**
+         * SAML 1.x Artifact binding/profile message decoder
+         */
+        class SAML_API SAML1ArtifactDecoder : public MessageDecoder
+        {
+        public:
+            SAML1ArtifactDecoder(const DOMElement* e);
+            virtual ~SAML1ArtifactDecoder();
+            
+            Response* decode(
+                std::string& relayState,
+                const saml2md::RoleDescriptor*& issuer,
+                bool& issuerTrusted,
+                const HTTPRequest& httpRequest,
+                const saml2md::MetadataProvider* metadataProvider=NULL,
+                const xmltooling::QName* role=NULL,
+                const TrustEngine* trustEngine=NULL
+                ) const;
+        };                
+
+    };
+};
index 464a17b..0ce6524 100644 (file)
@@ -43,7 +43,7 @@ namespace opensaml {
                 const HTTPRequest& httpRequest,
                 const saml2md::MetadataProvider* metadataProvider=NULL,
                 const xmltooling::QName* role=NULL,
-                const X509TrustEngine* trustEngine=NULL
+                const TrustEngine* trustEngine=NULL
                 ) const;
         };                
 
diff --git a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp
new file mode 100644 (file)
index 0000000..2d1b23c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *  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.
+ */
+
+/**
+ * SAML1ArtifactDecoder.cpp
+ * 
+ * SAML 1.x Artifact binding/profile message decoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml/binding/SAMLArtifact.h"
+#include "saml/binding/ReplayCache.h"
+#include "saml1/binding/SAML1ArtifactDecoder.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "security/X509TrustEngine.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml2md;
+using namespace opensaml::saml1p;
+using namespace opensaml::saml1;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml1p {              
+        MessageDecoder* SAML_DLLLOCAL SAML1ArtifactDecoderFactory(const DOMElement* const & e)
+        {
+            return new SAML1ArtifactDecoder(e);
+        }
+    };
+};
+
+SAML1ArtifactDecoder::SAML1ArtifactDecoder(const DOMElement* e) {}
+
+SAML1ArtifactDecoder::~SAML1ArtifactDecoder() {}
+
+Response* SAML1ArtifactDecoder::decode(
+    string& relayState,
+    const RoleDescriptor*& issuer,
+    bool& issuerTrusted,
+    const HTTPRequest& httpRequest,
+    const MetadataProvider* metadataProvider,
+    const QName* role,
+    const opensaml::TrustEngine* trustEngine
+    ) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("decode");
+#endif
+    Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1Artifact");
+
+    log.debug("validating input");
+    if (strcmp(httpRequest.getMethod(),"GET"))
+        return NULL;
+    vector<const char*> SAMLart;
+    const char* TARGET = httpRequest.getParameter("TARGET");
+    if (httpRequest.getParameters("SAMLart", SAMLart)==0 || !TARGET)
+        return NULL;
+    relayState = TARGET;
+
+    if (!m_artifactResolver || !metadataProvider)
+        throw BindingException("Artifact binding requires ArtifactResolver and MetadataProvider implementations be supplied.");
+
+    // Import the artifacts.
+    vector<SAMLArtifact*> artifacts;
+    for (vector<const char*>::const_iterator raw=SAMLart.begin(); raw!=SAMLart.end(); ++raw) {
+        try {
+            log.debug("processing encoded artifact (%s)", *raw);
+            
+            // Check replay.
+            ReplayCache* replayCache = SAMLConfig::getConfig().getReplayCache();
+            if (replayCache) {
+                if (!replayCache->check("SAML1Artifact", *raw, time(NULL) + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
+                    log.error("replay detected of artifact (%s)", *raw);
+                    throw BindingException("Rejecting replayed artifact ($1).", params(1,*raw));
+                }
+            }
+            else
+                log.warn("replay cache was not provided, this is a serious security risk!");
+
+            artifacts.push_back(SAMLArtifact::parse(*raw));
+        }
+        catch (ArtifactException&) {
+            log.error("error parsing artifact (%s)", *raw);
+            for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+            throw;
+        }
+        catch (XMLToolingException&) {
+            for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+            throw;
+        }
+    }
+    
+    issuer = NULL;
+    issuerTrusted = false;
+    log.debug("attempting to determine source of artifact(s)...");
+    const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(artifacts.front());
+    if (!provider) {
+        log.error(
+            "metadata lookup failed, unable to determine issuer of artifact (0x%s)",
+            SAMLArtifact::toHex(artifacts.front()->getBytes()).c_str()
+            );
+        for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+        throw BindingException("Metadata lookup failed, unable to determine artifact issuer");
+    }
+    
+    if (log.isDebugEnabled()) {
+        auto_ptr_char issuer(provider->getEntityID());
+        log.debug("lookup succeeded, artifact issued by (%s)", issuer.get());
+    }
+    
+    log.debug("attempting to find artifact issuing role...");
+    issuer=provider->getRoleDescriptor(*role, SAMLConstants::SAML11_PROTOCOL_ENUM);
+    if (!issuer)
+        issuer=provider->getRoleDescriptor(*role, SAMLConstants::SAML10_PROTOCOL_ENUM);
+    if (!issuer || !dynamic_cast<const IDPSSODescriptor*>(issuer)) {
+        log.error("unable to find compatible SAML role (%s) in metadata", role->toString().c_str());
+        for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+        BindingException ex("Unable to find compatible metadata role for artifact issuer.");
+        annotateException(&ex,provider); // throws it
+    }
+    
+    try {
+        auto_ptr<Response> response(
+            m_artifactResolver->resolve(
+                issuerTrusted,
+                artifacts,
+                dynamic_cast<const IDPSSODescriptor&>(*issuer),
+                dynamic_cast<const X509TrustEngine*>(trustEngine)
+                )
+            );
+        
+        if (trustEngine && response->getSignature()) {
+            issuerTrusted = trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver());
+            if (!issuerTrusted) {
+                log.error("unable to verify signature on message with supplied trust engine");
+                throw BindingException("Message signature failed verification.");
+            }
+        }
+        else if (!issuerTrusted) {
+            log.warn("unable to verify integrity of the message, leaving untrusted");
+        }
+        
+        for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+        return response.release();
+    }
+    catch (XMLToolingException& ex) {
+        for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
+        annotateException(&ex,issuer,false);
+        throw;
+    }
+}
index 83f893c..de0deaa 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * SAML1POSTDecoder.cpp
  * 
- * SAML 1.x POST binding/profile message encoder
+ * SAML 1.x POST binding/profile message decoder
  */
 
 #include "internal.h"
@@ -61,7 +61,7 @@ Response* SAML1POSTDecoder::decode(
     const HTTPRequest& httpRequest,
     const MetadataProvider* metadataProvider,
     const QName* role,
-    const X509TrustEngine* trustEngine
+    const opensaml::TrustEngine* trustEngine
     ) const
 {
 #ifdef _DEBUG
@@ -153,7 +153,7 @@ Response* SAML1POSTDecoder::decode(
                     );
                 if (issuer) {
                     if (trustEngine && response->getSignature()) {
-                        issuerTrusted = static_cast<const TrustEngine*>(trustEngine)->validate(
+                        issuerTrusted = trustEngine->validate(
                             *(response->getSignature()), *issuer, metadataProvider->getKeyResolver()
                             );
                         if (!issuerTrusted) {
index 4e49c2b..19cc520 100644 (file)
@@ -41,7 +41,7 @@ namespace opensaml {
                 const HTTPRequest& httpRequest,
                 const saml2md::MetadataProvider* metadataProvider=NULL,
                 const xmltooling::QName* role=NULL,
-                const X509TrustEngine* trustEngine=NULL
+                const TrustEngine* trustEngine=NULL
                 ) const;
         };                
 
index bf7b55d..7fedc01 100644 (file)
@@ -62,7 +62,7 @@ XMLObject* SAML2POSTDecoder::decode(
     const HTTPRequest& httpRequest,
     const MetadataProvider* metadataProvider,
     const QName* role,
-    const X509TrustEngine* trustEngine
+    const opensaml::TrustEngine* trustEngine
     ) const
 {
 #ifdef _DEBUG
@@ -182,9 +182,7 @@ XMLObject* SAML2POSTDecoder::decode(
             issuer=provider->getRoleDescriptor(*role, SAMLConstants::SAML20P_NS);
             if (issuer) {
                 if (trustEngine && signature) {
-                    issuerTrusted = static_cast<const TrustEngine*>(trustEngine)->validate(
-                        *signature, *issuer, metadataProvider->getKeyResolver()
-                        );
+                    issuerTrusted = trustEngine->validate(*signature, *issuer, metadataProvider->getKeyResolver());
                     if (!issuerTrusted) {
                         log.error("unable to verify signature on message with supplied trust engine");
                         throw BindingException("Message signature failed verification.");
index 994fa31..8f2aa30 100644 (file)
@@ -29,23 +29,20 @@ class ArtifactMapTest : public CxxTest::TestSuite
 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
+        \r
+        ArtifactMap* artifactMap = SAMLConfig::getConfig().getArtifactMap();\r
         artifactMap->storeContent(response.get(), &artifact, providerIdStr.c_str());\r
         response.release();\r
 \r
diff --git a/samltest/data/saml1/binding/SAML1Assertion.xml b/samltest/data/saml1/binding/SAML1Assertion.xml
new file mode 100644 (file)
index 0000000..93167ef
--- /dev/null
@@ -0,0 +1,6 @@
+<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="aident"
+IssueInstant="1970-01-02T01:01:02.100Z" Issuer="https://idp.example.org/" MajorVersion="1" MinorVersion="1">
+    <saml:AuthenticationStatement AuthenticationInstant="1970-01-02T01:01:02.100Z" AuthenticationMethod="method">
+        <saml:Subject><saml:NameIdentifier>John Doe</saml:NameIdentifier></saml:Subject>
+    </saml:AuthenticationStatement>
+</saml:Assertion>
diff --git a/samltest/saml1/binding/SAML1ArtifactTest.h b/samltest/saml1/binding/SAML1ArtifactTest.h
new file mode 100644 (file)
index 0000000..decc34f
--- /dev/null
@@ -0,0 +1,142 @@
+/*\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 "binding.h"\r
+\r
+#include <saml/binding/ArtifactMap.h>\r
+#include <saml/saml1/core/Protocols.h>\r
+#include <saml/saml1/binding/SAMLArtifactType0001.h>\r
+\r
+using namespace opensaml::saml1p;\r
+using namespace opensaml::saml1;\r
+\r
+class SAML1ArtifactTest : public CxxTest::TestSuite,\r
+    public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {\r
+public:\r
+    void setUp() {\r
+        m_fields.clear();\r
+        SAMLBindingBaseTestCase::setUp();\r
+    }\r
+\r
+    void tearDown() {\r
+        m_fields.clear();\r
+        SAMLBindingBaseTestCase::tearDown();\r
+    }\r
+\r
+    void testSAML1Artifact() {\r
+        try {\r
+            // Read message to use from file.\r
+            string path = data_path + "saml1/binding/SAML1Assertion.xml";\r
+            ifstream in(path.c_str());\r
+            DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+            XercesJanitor<DOMDocument> janitor(doc);\r
+            auto_ptr<Assertion> toSend(\r
+                dynamic_cast<Assertion*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))\r
+                );\r
+            janitor.release();\r
+\r
+            // Encode message.\r
+            auto_ptr<MessageEncoder> encoder(SAMLConfig::getConfig().MessageEncoderManager.newPlugin(SAML1_ARTIFACT_ENCODER, NULL));\r
+            encoder->setArtifactGenerator(this);\r
+            encoder->encode(m_fields,toSend.get(),"https://sp.example.org/","state",m_creds);\r
+            toSend.release();\r
+            \r
+            // Decode message.\r
+            string relayState;\r
+            const RoleDescriptor* issuer=NULL;\r
+            bool trusted=false;\r
+            QName idprole(SAMLConstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
+            auto_ptr<MessageDecoder> decoder(SAMLConfig::getConfig().MessageDecoderManager.newPlugin(SAML1_ARTIFACT_DECODER, NULL));\r
+            decoder->setArtifactResolver(this);\r
+            Locker locker(m_metadata);\r
+            auto_ptr<Response> response(\r
+                dynamic_cast<Response*>(\r
+                    decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust)\r
+                    )\r
+                );\r
+            \r
+            // Test the results.\r
+            TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");\r
+            TSM_ASSERT("SAML Response not decoded successfully.", response.get());\r
+            TSM_ASSERT("Message was not verified.", issuer && trusted);\r
+            auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());\r
+            TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));\r
+            TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);\r
+\r
+            // Trigger a replay.\r
+            TSM_ASSERT_THROWS("Did not catch the replay.", \r
+                decoder->decode(relayState,issuer,trusted,*this,m_metadata,&idprole,m_trust),\r
+                BindingException);\r
+        }\r
+        catch (XMLToolingException& ex) {\r
+            TS_TRACE(ex.what());\r
+            throw;\r
+        }\r
+    }\r
+\r
+    const char* getMethod() const {\r
+        return "GET";\r
+    } \r
+\r
+    const char* getRequestURL() const {\r
+        return "https://sp.example.org/SAML/Artifact";\r
+    }\r
+    \r
+    const char* getQueryString() const {\r
+        return NULL;\r
+    }\r
+    \r
+    SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {\r
+        return new SAMLArtifactType0001(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"));\r
+    }\r
+    \r
+    saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const {\r
+        throw BindingException("Not implemented.");\r
+    }\r
+    \r
+    Response* resolve(\r
+        bool& authenticated,\r
+        const vector<SAMLArtifact*>& artifacts,\r
+        const IDPSSODescriptor& idpDescriptor,\r
+        const X509TrustEngine* trustEngine=NULL\r
+        ) const {\r
+        TSM_ASSERT_EQUALS("Too many artifacts.", artifacts.size(), 1);\r
+        XMLObject* xmlObject =\r
+            SAMLConfig::getConfig().getArtifactMap()->retrieveContent(artifacts.front(), "https://sp.example.org/");\r
+        Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);\r
+        TSM_ASSERT("Not an assertion.", assertion!=NULL);\r
+        auto_ptr<Response> response(ResponseBuilder::buildResponse());\r
+        response->getAssertions().push_back(assertion);\r
+        Status* status = StatusBuilder::buildStatus();\r
+        response->setStatus(status);\r
+        StatusCode* sc = StatusCodeBuilder::buildStatusCode();\r
+        status->setStatusCode(sc);\r
+        sc->setValue(&StatusCode::SUCCESS);\r
+        response->marshall();\r
+        SchemaValidators.validate(response.get());\r
+        authenticated = true;\r
+        return response.release();\r
+    }\r
+\r
+    XMLObject* resolve(\r
+        bool& authenticated,\r
+        const saml2p::SAML2Artifact& artifact,\r
+        const SSODescriptorType& ssoDescriptor,\r
+        const X509TrustEngine* trustEngine=NULL\r
+        ) const {\r
+        throw BindingException("Not implemented.");\r
+    }\r
+};\r
index 938f1e8..741a9e0 100644 (file)
@@ -16,6 +16,7 @@
 \r
 #include "internal.h"\r
 #include <saml/SAMLConfig.h>\r
+#include <saml/binding/ArtifactMap.h>\r
 #include <saml/binding/ReplayCache.h>\r
 \r
 #include <fstream>\r
@@ -33,6 +34,7 @@ public:
         if (!SAMLConfig::getConfig().init())\r
             return false;\r
         SAMLConfig::getConfig().setReplayCache(new ReplayCache());\r
+        SAMLConfig::getConfig().setArtifactMap(new ArtifactMap());\r
 \r
         if (getenv("SAMLTEST_DATA"))\r
             data_path=std::string(getenv("SAMLTEST_DATA")) + "/";\r
index b282259..7f6e2c8 100644 (file)
                                        Name="binding"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1ArtifactTest.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml1\binding\SAML1POSTTest.cpp"\r
                                                >\r
                                        </File>\r
                                        Name="bnding"\r
                                        >\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1ArtifactTest.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=".\saml1\binding\SAML1POSTTest.h"\r
                                                >\r
                                                <FileConfiguration\r