ReplayCache, some decoder work, and merged schema validators into one suite.
authorScott Cantor <cantor.2@osu.edu>
Mon, 2 Oct 2006 05:22:30 +0000 (05:22 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 2 Oct 2006 05:22:30 +0000 (05:22 +0000)
23 files changed:
saml/Makefile.am
saml/SAMLConfig.cpp
saml/SAMLConfig.h
saml/binding/MessageDecoder.h [new file with mode: 0644]
saml/binding/MessageEncoder.h
saml/binding/ReplayCache.h [new file with mode: 0644]
saml/binding/impl/MessageDecoder.cpp [new file with mode: 0644]
saml/binding/impl/ReplayCache.cpp [new file with mode: 0644]
saml/exceptions.h
saml/saml.vcproj
saml/saml1/binding/SAML1POSTDecoder.h [new file with mode: 0644]
saml/saml1/binding/impl/SAML1POSTDecoder.cpp [new file with mode: 0644]
saml/saml1/core/Assertions.h
saml/saml1/core/Protocols.h
saml/saml1/core/impl/AssertionsSchemaValidators.cpp
saml/saml1/core/impl/ProtocolsSchemaValidators.cpp
saml/saml2/core/Assertions.h
saml/saml2/core/Protocols.h
saml/saml2/core/impl/Assertions20SchemaValidators.cpp
saml/saml2/core/impl/Protocols20SchemaValidators.cpp
saml/saml2/metadata/Metadata.h
saml/saml2/metadata/impl/MetadataImpl.cpp
saml/saml2/metadata/impl/MetadataSchemaValidators.cpp

index cc3ee2d..d0ebc77 100644 (file)
@@ -32,7 +32,9 @@ libsamlinclude_HEADERS = \
 
 samlbindinclude_HEADERS = \
        binding/ArtifactMap.h \
+       binding/MessageDecoder.h \
        binding/MessageEncoder.h \
+       binding/ReplayCache.h \
        binding/SAMLArtifact.h \
        binding/URLEncoder.h
 
@@ -88,6 +90,9 @@ noinst_HEADERS = \
 libsaml_la_SOURCES = \
        SAMLConfig.cpp \
        binding/impl/ArtifactMap.cpp \
+       binding/impl/MessageDecoder.cpp \
+       binding/impl/MessageEncoder.cpp \
+       binding/impl/ReplayCache.cpp \
        binding/impl/SAMLArtifact.cpp \
        binding/impl/URLEncoder.cpp \
        saml1/core/impl/AssertionsImpl.cpp \
@@ -97,6 +102,7 @@ libsaml_la_SOURCES = \
        saml1/binding/impl/SAMLArtifactType0001.cpp \
        saml1/binding/impl/SAMLArtifactType0002.cpp \
        saml1/binding/impl/SAML1ArtifactEncoder.cpp \
+       saml1/binding/impl/SAML1POSTDecoder.cpp \
        saml1/binding/impl/SAML1POSTEncoder.cpp \
        saml2/core/impl/Assertions20Impl.cpp \
        saml2/core/impl/Assertions20SchemaValidators.cpp \
index 5d68230..4e4c7ce 100644 (file)
@@ -25,7 +25,9 @@
 #include "exceptions.h"
 #include "SAMLConfig.h"
 #include "binding/ArtifactMap.h"
+#include "binding/MessageDecoder.h"
 #include "binding/MessageEncoder.h"
+#include "binding/ReplayCache.h"
 #include "binding/SAMLArtifact.h"
 #include "binding/URLEncoder.h"
 #include "saml1/core/Assertions.h"
@@ -96,6 +98,12 @@ void SAMLConfig::setURLEncoder(URLEncoder* urlEncoder)
     m_urlEncoder = urlEncoder;
 }
 
+void SAMLConfig::setReplayCache(ReplayCache* replayCache)
+{
+    delete m_replayCache;
+    m_replayCache = replayCache;
+}
+
 bool SAMLInternalConfig::init(bool initXMLTooling)
 {
 #ifdef _DEBUG
@@ -113,8 +121,6 @@ bool SAMLInternalConfig::init(bool initXMLTooling)
     REGISTER_EXCEPTION_FACTORY(MetadataFilterException,opensaml::saml2md);
     REGISTER_EXCEPTION_FACTORY(BindingException,opensaml);
 
-    registerMessageEncoders();
-    registerSAMLArtifacts();
     saml1::registerAssertionClasses();
     saml1p::registerProtocolClasses();
     saml2::registerAssertionClasses();
@@ -122,7 +128,10 @@ bool SAMLInternalConfig::init(bool initXMLTooling)
     saml2md::registerMetadataClasses();
     saml2md::registerMetadataProviders();
     saml2md::registerMetadataFilters();
+    registerSAMLArtifacts();
     registerTrustEngines();
+    registerMessageEncoders();
+    registerMessageDecoders();
     
     m_urlEncoder = new URLEncoder();
 
@@ -137,21 +146,19 @@ void SAMLInternalConfig::term(bool termXMLTooling)
 #endif
     Category& log=Category::getInstance(SAML_LOGCAT".SAMLConfig");
 
-    saml1::AssertionSchemaValidators.destroyValidators();
-    saml1p::ProtocolSchemaValidators.destroyValidators();
-    saml2::AssertionSchemaValidators.destroyValidators();
-    saml2md::MetadataSchemaValidators.destroyValidators();
-    
+    MessageDecoderManager.deregisterFactories();
+    MessageEncoderManager.deregisterFactories();
     TrustEngineManager.deregisterFactories();
+    SAMLArtifactManager.deregisterFactories();
     MetadataFilterManager.deregisterFactories();
     MetadataProviderManager.deregisterFactories();
-    SAMLArtifactManager.deregisterFactories();
-    MessageEncoderManager.deregisterFactories();
 
     delete m_artifactMap;
     m_artifactMap = NULL;
     delete m_urlEncoder;
     m_urlEncoder = NULL;
+    delete m_replayCache;
+    m_replayCache = NULL;
 
     if (termXMLTooling) {
         XMLToolingConfig::getConfig().term();
@@ -236,3 +243,98 @@ void opensaml::log_openssl()
         code=ERR_get_error_line_data(&file,&line,&data,&flags);
     }
 }
+
+using namespace saml2md;
+
+void opensaml::annotateException(XMLToolingException* e, const EntityDescriptor* entity, bool rethrow)
+{
+    if (entity) {
+        auto_ptr_char id(entity->getEntityID());
+        e->addProperty("entityID",id.get());
+        const list<XMLObject*>& roles=entity->getOrderedChildren();
+        for (list<XMLObject*>::const_iterator child=roles.begin(); child!=roles.end(); ++child) {
+            const RoleDescriptor* role=dynamic_cast<RoleDescriptor*>(*child);
+            if (role && role->isValid()) {
+                const vector<ContactPerson*>& contacts=role->getContactPersons();
+                for (vector<ContactPerson*>::const_iterator c=contacts.begin(); c!=contacts.end(); ++c) {
+                    const XMLCh* ctype=(*c)->getContactType();
+                    if (ctype && (XMLString::equals(ctype,ContactPerson::CONTACT_SUPPORT)
+                            || XMLString::equals(ctype,ContactPerson::CONTACT_TECHNICAL))) {
+                        GivenName* fname=(*c)->getGivenName();
+                        SurName* lname=(*c)->getSurName();
+                        auto_ptr_char first(fname ? fname->getName() : NULL);
+                        auto_ptr_char last(lname ? lname->getName() : NULL);
+                        if (first.get() && last.get()) {
+                            string contact=string(first.get()) + ' ' + last.get();
+                            e->addProperty("contactName",contact.c_str());
+                        }
+                        else if (first.get())
+                            e->addProperty("contactName",first.get());
+                        else if (last.get())
+                            e->addProperty("contactName",last.get());
+                        const vector<EmailAddress*>& emails=const_cast<const ContactPerson*>(*c)->getEmailAddresss();
+                        if (!emails.empty()) {
+                            auto_ptr_char email(emails.front()->getAddress());
+                            if (email.get())
+                                e->addProperty("contactEmail",email.get());
+                        }
+                        break;
+                    }
+                }
+                if (e->getProperty("contactName") || e->getProperty("contactEmail")) {
+                    auto_ptr_char eurl(role->getErrorURL());
+                    if (eurl.get()) {
+                        e->addProperty("errorURL",eurl.get());
+                    }
+                }
+                break;
+            }
+        }
+    }
+    
+    if (rethrow)
+        e->raise();
+}
+
+void opensaml::annotateException(XMLToolingException* e, const RoleDescriptor* role, bool rethrow)
+{
+    if (role) {
+        auto_ptr_char id(dynamic_cast<EntityDescriptor*>(role->getParent())->getEntityID());
+        e->addProperty("entityID",id.get());
+
+        const vector<ContactPerson*>& contacts=role->getContactPersons();
+        for (vector<ContactPerson*>::const_iterator c=contacts.begin(); c!=contacts.end(); ++c) {
+            const XMLCh* ctype=(*c)->getContactType();
+            if (ctype && (XMLString::equals(ctype,ContactPerson::CONTACT_SUPPORT)
+                    || XMLString::equals(ctype,ContactPerson::CONTACT_TECHNICAL))) {
+                GivenName* fname=(*c)->getGivenName();
+                SurName* lname=(*c)->getSurName();
+                auto_ptr_char first(fname ? fname->getName() : NULL);
+                auto_ptr_char last(lname ? lname->getName() : NULL);
+                if (first.get() && last.get()) {
+                    string contact=string(first.get()) + ' ' + last.get();
+                    e->addProperty("contactName",contact.c_str());
+                }
+                else if (first.get())
+                    e->addProperty("contactName",first.get());
+                else if (last.get())
+                    e->addProperty("contactName",last.get());
+                const vector<EmailAddress*>& emails=const_cast<const ContactPerson*>(*c)->getEmailAddresss();
+                if (!emails.empty()) {
+                    auto_ptr_char email(emails.front()->getAddress());
+                    if (email.get())
+                        e->addProperty("contactEmail",email.get());
+                }
+                break;
+            }
+        }
+
+        auto_ptr_char eurl(role->getErrorURL());
+        if (eurl.get()) {
+            e->addProperty("errorURL",eurl.get());
+        }
+    }
+    
+    if (rethrow)
+        e->raise();
+}
index 1d0dbd1..8491d0f 100644 (file)
@@ -39,6 +39,7 @@ namespace opensaml {
     class SAML_API ArtifactMap;\r
     class SAML_API MessageEncoder;\r
     class SAML_API MessageDecoder;\r
+    class SAML_API ReplayCache;\r
     class SAML_API SAMLArtifact;\r
     class SAML_API TrustEngine;\r
     class SAML_API URLEncoder;\r
@@ -106,7 +107,7 @@ namespace opensaml {
         /**\r
          * Returns the global ArtifactMap instance.\r
          * \r
-         * @return  global ArtifactMap\r
+         * @return  global ArtifactMap or NULL\r
          */\r
         ArtifactMap* getArtifactMap() const {\r
             return m_artifactMap;\r
@@ -124,13 +125,31 @@ namespace opensaml {
         /**\r
          * Returns the global URLEncoder instance.\r
          * \r
-         * @return  global URLEncoder\r
+         * @return  global URLEncoder or NULL\r
          */\r
         URLEncoder* getURLEncoder() const {\r
             return m_urlEncoder;\r
         }\r
         \r
         /**\r
+         * Sets the global ReplayCache 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 replayCache   new ReplayCache instance to store\r
+         */\r
+        void setReplayCache(ReplayCache* replayCache);\r
+\r
+        /**\r
+         * Returns the global ReplayCache instance.\r
+         * \r
+         * @return  global ReplayCache or NULL\r
+         */\r
+        ReplayCache* getReplayCache() const {\r
+            return m_replayCache;\r
+        }\r
+        \r
+        /**\r
          * Generate random information using the underlying security library\r
          * \r
          * @param buf   buffer for the information\r
@@ -195,13 +214,16 @@ namespace opensaml {
         xmltooling::PluginManager<saml2md::MetadataFilter,const DOMElement*> MetadataFilterManager;\r
 \r
     protected:\r
-        SAMLConfig() : m_artifactMap(NULL), m_urlEncoder(NULL) {}\r
+        SAMLConfig() : m_artifactMap(NULL), m_urlEncoder(NULL), m_replayCache(NULL) {}\r
         \r
         /** Global ArtifactMap instance for use by artifact-related functions. */\r
         ArtifactMap* m_artifactMap;\r
 \r
         /** Global URLEncoder instance for use by URL-related functions. */\r
         URLEncoder* m_urlEncoder;\r
+        \r
+        /** Global ReplayCache instance. */\r
+        ReplayCache* m_replayCache;\r
     };\r
 \r
 #if defined (_MSC_VER)\r
diff --git a/saml/binding/MessageDecoder.h b/saml/binding/MessageDecoder.h
new file mode 100644 (file)
index 0000000..609273f
--- /dev/null
@@ -0,0 +1,249 @@
+/*\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/MessageDecoder.h\r
+ * \r
+ * Interface to SAML protocol binding message decoders. \r
+ */\r
+\r
+#ifndef __saml_decoder_h__\r
+#define __saml_decoder_h__\r
+\r
+#include <saml/base.h>\r
+\r
+#include <xmltooling/XMLObject.h>\r
+\r
+namespace opensaml {\r
+    \r
+    class SAML_API SAMLArtifact;\r
+    class SAML_API X509TrustEngine;\r
+    namespace saml1p {\r
+        class SAML_API Response;\r
+    };\r
+    namespace saml2p {\r
+        class SAML_API SAML2Artifact;\r
+    };\r
+    namespace saml2md {\r
+        class SAML_API MetadataProvider;\r
+        class SAML_API IDPSSODescriptor;\r
+        class SAML_API RoleDescriptor;\r
+        class SAML_API SSODescriptorType;\r
+    }\r
+\r
+    /**\r
+     * Interface to SAML protocol binding message decoders.\r
+     */\r
+    class SAML_API MessageDecoder\r
+    {\r
+        MAKE_NONCOPYABLE(MessageDecoder);\r
+    public:\r
+        virtual ~MessageDecoder() {}\r
+\r
+        /**\r
+         * Interface to caller-supplied shim for accessing HTTP request context.\r
+         * \r
+         * To supply information from the surrounding web server environment,\r
+         * a shim must be supplied in the form of this interface to adapt the\r
+         * library to different proprietary server APIs.\r
+         */\r
+        class SAML_API HTTPRequest {\r
+            MAKE_NONCOPYABLE(HTTPRequest);\r
+        protected:\r
+            HTTPRequest() {}\r
+        public:\r
+            virtual ~HTTPRequest() {}\r
+            \r
+            /**\r
+             * Returns the HTTP method of the request (GET, POST, etc.)\r
+             * \r
+             * @return the HTTP method\r
+             */\r
+            virtual const char* getMethod() const=0;\r
+            \r
+            /**\r
+             * Returns the complete request URL, including scheme, host, port.\r
+             * \r
+             * @return the request URL\r
+             */\r
+            virtual const char* getRequestURL() const=0;\r
+            \r
+            /**\r
+             * Returns the HTTP query string appened to the request. The query\r
+             * string is returned without any decoding applied, everything found\r
+             * after the ? delimiter. \r
+             * \r
+             * @return the query string\r
+             */\r
+            virtual const char* getQueryString() const=0;\r
+            \r
+            /**\r
+             * Returns a decoded named parameter value from the query string or form body.\r
+             * If a parameter has multiple values, only one will be returned.\r
+             * \r
+             * @param name  the name of the parameter to return\r
+             * @return a single parameter value or NULL\r
+             */\r
+            virtual const char* getParameter(const char* name) const=0;\r
+\r
+            /**\r
+             * Returns all of the decoded values of a named parameter from the query string\r
+             * or form body. All values found will be returned.\r
+             * \r
+             * @param name      the name of the parameter to return\r
+             * @param values    a vector in which to return pointers to the decoded values\r
+             * @return  the number of values returned\r
+             */            \r
+            virtual std::vector<const char*>::size_type getParameters(\r
+                const char* name, std::vector<const char*>& values\r
+                ) const=0;\r
+        };\r
+\r
+        /**\r
+         * Interface to caller-supplied artifact resolution mechanism.\r
+         * \r
+         * Resolving artifacts requires internally performing a SOAP-based\r
+         * call to the artifact source, usually in a mutually authenticated fashion.\r
+         * The potential options vary widely, so the work is encapsulated by this\r
+         * interface, though of course other library facilities may be used.\r
+         * \r
+         * <p>A MessageDecoder implementation will invoke the supplied interface\r
+         * when it requires an artifact be resolved.\r
+         */\r
+        class SAML_API ArtifactResolver {\r
+            MAKE_NONCOPYABLE(ArtifactResolver);\r
+        protected:\r
+            ArtifactResolver() {}\r
+        public:\r
+            virtual ~ArtifactResolver() {}\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 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
+                const saml2md::IDPSSODescriptor& idpDescriptor,\r
+                const X509TrustEngine* trustEngine=NULL\r
+                ) const=0;\r
+\r
+            /**\r
+             * Resolves a SAML 2.0 artifact into the corresponding SAML protocol message.\r
+             * The caller is responsible for the resulting XMLObject.\r
+             * \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
+                const saml2p::SAML2Artifact& artifact,\r
+                const saml2md::SSODescriptorType& ssoDescriptor,\r
+                const X509TrustEngine* trustEngine=NULL\r
+                ) const=0;\r
+        };\r
+\r
+        /**\r
+         * Provides an ArtifactResolver implementation for the MessageDecoder 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 artifactResolver   an ArtifactResolver implementation to use\r
+         */\r
+        void setArtifactResolver(ArtifactResolver* artifactResolver) {\r
+            m_artifactResolver = artifactResolver;\r
+        }\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 decoder should use a validating XML parser\r
+         */\r
+        void setValidating(bool validate=true) {\r
+            m_validate = validate;\r
+        }\r
+\r
+        /**\r
+         * Decodes an HTTP request into a SAML protocol message, and returns related\r
+         * information about the issuer of the message and whether it can be trusted.\r
+         * If the HTTP request does not contain the information necessary to decode\r
+         * the request, a NULL will be returned. Errors during the decoding process\r
+         * will be raised as exceptions.\r
+         * \r
+         * <p>Artifact-based bindings require an ArtifactResolver be set to\r
+         * turn an artifact into the corresponding message.\r
+         * \r
+         * <p>In some cases, a message may be returned but not authenticated. The caller\r
+         * should examine the issuerTrusted output value to establish this.  \r
+         * \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 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
+         * @return  the decoded message, or NULL if the decoder did not recognize the request content\r
+         */\r
+        virtual xmltooling::XMLObject* decode(\r
+            std::string& relayState,\r
+            const saml2md::RoleDescriptor*& issuer,\r
+            bool& issuerTrusted,\r
+            const HTTPRequest& httpRequest,\r
+            const saml2md::MetadataProvider* metadataProvider=NULL,\r
+            const xmltooling::QName* role=NULL,\r
+            const X509TrustEngine* 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
+        \r
+        /** Flag controlling schema validation. */\r
+        bool m_validate;\r
+    };\r
+\r
+    /**\r
+     * Registers MessageDecoder plugins into the runtime.\r
+     */\r
+    void SAML_API registerMessageDecoders();\r
+\r
+    /** MessageDecoder for SAML 1.x Browser/Artifact "binding" (really part of profile) */\r
+    #define SAML1_ARTIFACT_DECODER  "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"\r
+\r
+    /** MessageDecoder for SAML 1.x Browser/POST "binding" (really part of profile) */\r
+    #define SAML1_POST_DECODER  "urn:oasis:names:tc:SAML:1.0:profiles:browser-post"\r
+    \r
+    /** MessageDecoder for SAML 2.0 HTTP-Artifact binding */\r
+    #define SAML2_ARTIFACT_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"\r
+\r
+    /** MessageDecoder for SAML 2.0 HTTP-POST binding */\r
+    #define SAML2_POST_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"\r
+\r
+    /** MessageDecoder for SAML 2.0 HTTP-Redirect binding */\r
+    #define SAML2_REDIRECT_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"\r
+};\r
+\r
+#endif /* __saml_decoder_h__ */\r
index 2a5fc71..acfdf15 100644 (file)
@@ -29,7 +29,6 @@
 #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
@@ -54,7 +53,7 @@ namespace opensaml {
          * 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
+         * A MessageEncoder implementation will invoke the supplied generator interface\r
          * when it requires an artifact be created.\r
          */\r
         class SAML_API ArtifactGenerator {\r
diff --git a/saml/binding/ReplayCache.h b/saml/binding/ReplayCache.h
new file mode 100644 (file)
index 0000000..d5655fd
--- /dev/null
@@ -0,0 +1,67 @@
+/*\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/ReplayCache.h\r
+ * \r
+ * Helper class on top of StorageService for detecting message replay.\r
+ */\r
+\r
+#ifndef __saml_replay_h__\r
+#define __saml_replay_h__\r
+\r
+#include <saml/base.h>\r
+#include <xmltooling/util/StorageService.h>\r
+\r
+namespace opensaml {\r
+\r
+    /**\r
+     * Helper class on top of StorageService for detecting message replay.\r
+     */\r
+    class SAML_API ReplayCache\r
+    {\r
+        MAKE_NONCOPYABLE(ReplayCache);\r
+    public:\r
+        \r
+        /**\r
+         * Creates a replay cache on top of a particular StorageService.\r
+         * \r
+         * @param storage       pointer to a StorageService, or NULL to keep cache in memory\r
+         */\r
+        ReplayCache(xmltooling::StorageService* storage=NULL);\r
+\r
+        virtual ~ReplayCache();\r
+        \r
+        /**\r
+         * Returns true iff the check value is not found in the cache, and stores it.\r
+         * \r
+         * @param context   a context label to subdivide the cache\r
+         * @param s         value to check\r
+         * @param expires   time for disposal of value from cache\r
+         */\r
+        virtual bool check(const char* context, const char* s, time_t expires);\r
+    \r
+        bool check(const char* context, const XMLCh* str, time_t expires) {\r
+            xmltooling::auto_ptr_char temp(str);\r
+            return check(context, temp.get(), expires);\r
+        }\r
+        \r
+    private:\r
+        xmltooling::StorageService* m_storage;\r
+    };\r
+};\r
+\r
+#endif /* __saml_replay_h__ */\r
diff --git a/saml/binding/impl/MessageDecoder.cpp b/saml/binding/impl/MessageDecoder.cpp
new file mode 100644 (file)
index 0000000..0b87270
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+
+/**
+ * MessageDecoder.cpp
+ * 
+ * Interface to SAML protocol binding message decoders. 
+ */
+
+#include "internal.h"
+#include "binding/MessageDecoder.h"
+
+using namespace opensaml;
+using namespace xmltooling;
+
+namespace opensaml {
+    namespace saml1p {
+        SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML1ArtifactDecoderFactory;
+        SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML1POSTDecoderFactory;
+    }; 
+
+    namespace saml2p {
+        SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML2ArtifactDecoderFactory;
+        SAML_DLLLOCAL PluginManager<MessageDecoder,const DOMElement*>::Factory SAML2POSTDecoderFactory;
+    };
+};
+
+void SAML_API opensaml::registerMessageDecoders()
+{
+    SAMLConfig& conf=SAMLConfig::getConfig();
+    //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);
+}
diff --git a/saml/binding/impl/ReplayCache.cpp b/saml/binding/impl/ReplayCache.cpp
new file mode 100644 (file)
index 0000000..5081bce
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  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.
+ */
+
+/**
+ * ReplayCache.cpp
+ * 
+ * Helper class on top of StorageService for detecting message replay. 
+ */
+
+#include "internal.h"
+#include "binding/ReplayCache.h"
+
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+ReplayCache::ReplayCache(StorageService* storage) : m_storage(storage)
+{
+    if (!m_storage)
+        m_storage = XMLToolingConfig::getConfig().StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE, NULL);
+}
+
+ReplayCache::~ReplayCache()
+{
+    delete m_storage;
+}
+
+bool ReplayCache::check(const char* context, const char* s, time_t expires)
+{
+    // In storage already?
+    if (m_storage->readString(context, s))
+        return false;
+    m_storage->createText(context, s, "x", expires);
+    return true;
+}
index 186aa4e..b44102e 100644 (file)
 #include <xmltooling/exceptions.h>
 
 namespace opensaml {
+    
+    namespace saml2md {
+        class SAML_API EntityDescriptor;
+        class SAML_API RoleDescriptor;
+    };
+    
     DECL_XMLTOOLING_EXCEPTION(BindingException,SAML_EXCEPTIONAPI(SAML_API),opensaml,xmltooling::XMLToolingException,Exceptions in SAML binding processing);
+
+    /**
+     * Attaches metadata-derived information as exception properties and optionally
+     * rethrows the object. The following named properties are attached, when possible:
+     * 
+     *  <dl>
+     *  <dt>providerId</dt>     <dd>The unique ID of the entity</dd>
+     *  <dt>errorURL</dt>       <dd>The error support URL of a random role</dd>
+     *  <dt>contactName</dt>    <dd>A formatted support or technical contact name</dd>
+     *  <dt>contactEmail</dt>   <dd>A contact email address</dd>
+     *  </dl>
+     * 
+     * @param e         pointer to exception object
+     * @param entity    pointer to entity
+     * @param rethrow   true iff the exception should be rethrown
+     */
+    void SAML_API annotateException(
+        xmltooling::XMLToolingException* e, const saml2md::EntityDescriptor* entity, bool rethrow=true
+        );
+    
+    /**
+     * Attaches metadata-derived information as exception properties and optionally
+     * rethrows the object. The following named properties are attached, when possible:
+     * 
+     *  <dl>
+     *  <dt>providerId</dt>     <dd>The unique ID of the entity</dd>
+     *  <dt>errorURL</dt>       <dd>The error support URL of the role</dd>
+     *  <dt>contactName</dt>    <dd>A formatted support or technical contact name</dd>
+     *  <dt>contactEmail</dt>   <dd>A contact email address</dd>
+     *  </dl>
+     * 
+     * @param e         pointer to exception object
+     * @param entity    pointer to role
+     * @param rethrow   true iff the exception should be rethrown
+     */
+    void SAML_API annotateException(
+        xmltooling::XMLToolingException* e, const saml2md::RoleDescriptor* role, bool rethrow=true
+        );
 };
 
 #endif /* __saml_exceptions_h__ */
index 4a8d469..cbfd019 100644 (file)
                                                        >\r
                                                </File>\r
                                                <File\r
+                                                       RelativePath=".\saml1\binding\impl\SAML1POSTDecoder.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml1\binding\impl\SAML1POSTEncoder.cpp"\r
                                                        >\r
                                                </File>\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\binding\impl\MessageDecoder.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\binding\impl\MessageEncoder.cpp"\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\binding\impl\ReplayCache.cpp"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\binding\impl\SAMLArtifact.cpp"\r
                                                >\r
                                        </File>\r
                                                >\r
                                        </File>\r
                                        <File\r
+                                               RelativePath=".\saml1\binding\SAML1POSTDecoder.h"\r
+                                               >\r
+                                       </File>\r
+                                       <File\r
                                                RelativePath=".\saml1\binding\SAML1POSTEncoder.h"\r
                                                >\r
                                        </File>\r
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath=".\binding\MessageDecoder.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\binding\MessageEncoder.h"\r
                                        >\r
                                </File>\r
                                <File\r
+                                       RelativePath=".\binding\ReplayCache.h"\r
+                                       >\r
+                               </File>\r
+                               <File\r
                                        RelativePath=".\binding\SAMLArtifact.h"\r
                                        >\r
                                </File>\r
diff --git a/saml/saml1/binding/SAML1POSTDecoder.h b/saml/saml1/binding/SAML1POSTDecoder.h
new file mode 100644 (file)
index 0000000..464a17b
--- /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/SAML1POSTDecoder.h
+ * 
+ * SAML 1.x POST binding/profile message decoder
+ */
+
+#include <saml/binding/MessageDecoder.h>
+#include <saml/saml1/core/Protocols.h>
+
+
+namespace opensaml {
+    namespace saml1p {
+
+        /**
+         * SAML 1.x POST binding/profile message decoder
+         */
+        class SAML_API SAML1POSTDecoder : public MessageDecoder
+        {
+        public:
+            SAML1POSTDecoder(const DOMElement* e);
+            virtual ~SAML1POSTDecoder();
+            
+            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 X509TrustEngine* trustEngine=NULL
+                ) const;
+        };                
+
+    };
+};
diff --git a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp
new file mode 100644 (file)
index 0000000..b99ab68
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ *  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.
+ */
+
+/**
+ * SAML1POSTDecoder.cpp
+ * 
+ * SAML 1.x POST binding/profile message encoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml/binding/ReplayCache.h"
+#include "saml1/binding/SAML1POSTDecoder.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "security/X509TrustEngine.h"
+
+#include <log4cpp/Category.hh>
+#include <xercesc/util/Base64.hpp>
+#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 SAML1POSTDecoderFactory(const DOMElement* const & e)
+        {
+            return new SAML1POSTDecoder(e);
+        }
+    };
+};
+
+SAML1POSTDecoder::SAML1POSTDecoder(const DOMElement* e) {}
+
+SAML1POSTDecoder::~SAML1POSTDecoder() {}
+
+Response* SAML1POSTDecoder::decode(
+    string& relayState,
+    const RoleDescriptor*& issuer,
+    bool& issuerTrusted,
+    const HTTPRequest& httpRequest,
+    const MetadataProvider* metadataProvider,
+    const QName* role,
+    const X509TrustEngine* trustEngine
+    ) const
+{
+#ifdef _DEBUG
+    xmltooling::NDC ndc("decode");
+#endif
+    Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1POST");
+
+    log.debug("validating input");
+    if (strcmp(httpRequest.getMethod(),"POST"))
+        return NULL;
+    const char* samlResponse = httpRequest.getParameter("SAMLResponse");
+    const char* TARGET = httpRequest.getParameter("TARGET");
+    if (!samlResponse || !TARGET)
+        return NULL;
+    relayState = TARGET;
+
+    // Decode the base64 into SAML.
+    unsigned int x;
+    XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(samlResponse),&x);
+    if (!decoded)
+        throw BindingException("Unable to decode base64 in POST profile response.");
+    log.debug("decoded SAML response:\n%s", decoded);
+    istringstream is(reinterpret_cast<char*>(decoded));
+    XMLString::release(&decoded);
+    
+    // Parse and bind the document into an XMLObject.
+    DOMDocument* doc = (m_validate ? XMLToolingConfig::getConfig().getValidatingParser()
+        : XMLToolingConfig::getConfig().getParser()).parse(is); 
+    XercesJanitor<DOMDocument> janitor(doc);
+    auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
+    janitor.release();
+
+    Response* response = dynamic_cast<Response*>(xmlObject.get());
+    if (!response)
+        throw BindingException("Decoded message was not a SAML 1.x Response.");
+
+    try {
+        if (!m_validate)
+            SchemaValidators.validate(xmlObject.get());
+        
+        // Check recipient URL.
+        auto_ptr_char recipient(response->getRecipient());
+        const char* recipient2 = httpRequest.getRequestURL();
+        if (!recipient2 || !*recipient2 || strcmp(recipient.get(),recipient2)) {
+            log.error("POST targeted at (%s), but delivered to (%s)", recipient.get(), recipient2 ? recipient2 : "none");
+            throw BindingException("SAML message delivered with POST to incorrect server URL.");
+        }
+        
+        time_t now = time(NULL);
+        if (response->getIssueInstant()->getEpoch() < now-(2*XMLToolingConfig::getConfig().clock_skew_secs))
+            throw BindingException("Detected expired POST profile response.");
+            
+        ReplayCache* replayCache = SAMLConfig::getConfig().getReplayCache();
+        if (replayCache) {
+            auto_ptr_char id(response->getResponseID());
+            if (!replayCache->check("SAML1POST", id.get(), response->getIssueInstant()->getEpoch() + (2*XMLToolingConfig::getConfig().clock_skew_secs)))
+                throw BindingException("Rejecting replayed response ID ($1).", params(1,id.get()));
+        }
+        else
+            log.warn("replay cache was not provided, this is a serious security risk!");
+        
+        issuer = NULL;
+        issuerTrusted = false;
+        log.debug("attempting to establish issuer and integrity of message...");
+        const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
+        if (!assertions.empty()) {
+            const EntityDescriptor* provider=
+                metadataProvider ? metadataProvider->getEntityDescriptor(assertions.front()->getIssuer()) : NULL;
+            if (provider) {
+                pair<bool,int> minor = response->getMinorVersion();
+                issuer=provider->getRoleDescriptor(
+                    *role,
+                    (minor.first && minor.second==0) ? SAMLConstants::SAML10_PROTOCOL_ENUM : SAMLConstants::SAML11_PROTOCOL_ENUM
+                    );
+                if (issuer && trustEngine && response->getSignature()) {
+                    issuerTrusted = static_cast<const TrustEngine*>(trustEngine)->validate(
+                        *(response->getSignature()), *issuer, metadataProvider->getKeyResolver()
+                        );
+                    if (!issuerTrusted)
+                        log.error("signature on message could not be verified by supplied trust engine");
+                }
+                if (log.isDebugEnabled()) {
+                    auto_ptr_char iname(assertions.front()->getIssuer());
+                    log.debug("message from (%s), integrity %sverified", iname.get(), issuerTrusted ? "" : "NOT ");
+                }
+            }
+            else
+                log.warn("no metadata provider supplied, can't establish identity of issuer");
+        }
+        else
+            log.warn("no assertions found, can't establish identity of issuer");
+    }
+    catch (XMLToolingException& ex) {
+        // Check for an Issuer.
+        const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
+        if (!assertions.empty()) {
+            if (!metadataProvider) {
+                // Just record it.
+                auto_ptr_char issuer(assertions.front()->getIssuer());
+                if (issuer.get())
+                    ex.addProperty("entityID", issuer.get());
+                throw;  
+            }
+            // Try and locate metadata for error handling.
+            const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(assertions.front()->getIssuer(),false);
+            if (provider) {
+                pair<bool,int> minor = response->getMinorVersion();
+                const IDPSSODescriptor* role=provider->getIDPSSODescriptor(
+                    (minor.first && minor.second==0) ? SAMLConstants::SAML10_PROTOCOL_ENUM : SAMLConstants::SAML11_PROTOCOL_ENUM
+                    );
+                if (role) annotateException(&ex,role); // throws it
+                annotateException(&ex,provider);  // throws it
+            }
+        }
+    }
+
+    xmlObject.release();
+    return response;
+}
index a8fe0fe..53843d0 100644 (file)
@@ -263,11 +263,6 @@ namespace opensaml {
          * Registers builders and validators for SAML 1.x Assertion classes into the runtime.
          */
         void SAML_API registerAssertionClasses();
-
-        /**
-         * Validator suite for SAML 1.x Assertion schema validation.
-         */
-        extern SAML_API xmltooling::ValidatorSuite AssertionSchemaValidators;
     };
 };
 
index c3300b9..e30ff19 100644 (file)
@@ -159,11 +159,6 @@ namespace opensaml {
          * Registers builders and validators for SAML 1.x Protocol classes into the runtime.
          */
         void SAML_API registerProtocolClasses();
-
-        /**
-         * Validator suite for SAML 1.x Protocol schema validation.
-         */
-        extern SAML_API xmltooling::ValidatorSuite ProtocolSchemaValidators;
     };
 };
 
index df178bd..72a6143 100644 (file)
@@ -144,12 +144,12 @@ namespace opensaml {
 #define REGISTER_ELEMENT(cname) \
     q=QName(SAMLConstants::SAML1_NS,cname::LOCAL_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    AssertionSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
     
 #define REGISTER_TYPE(cname) \
     q=QName(SAMLConstants::SAML1_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    AssertionSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
 
 #define REGISTER_ELEMENT_NOVAL(cname) \
     q=QName(SAMLConstants::SAML1_NS,cname::LOCAL_NAME); \
@@ -159,8 +159,6 @@ namespace opensaml {
     q=QName(SAMLConstants::SAML1_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
 
-ValidatorSuite opensaml::saml1::AssertionSchemaValidators("AssertionSchemaValidators");
-
 void opensaml::saml1::registerAssertionClasses() {
     QName q;
     REGISTER_ELEMENT(Action);
index c52e988..445ec2b 100644 (file)
@@ -98,12 +98,12 @@ namespace opensaml {
 #define REGISTER_ELEMENT(cname) \
     q=QName(SAMLConstants::SAML1P_NS,cname::LOCAL_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    ProtocolSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
     
 #define REGISTER_TYPE(cname) \
     q=QName(SAMLConstants::SAML1P_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    ProtocolSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
 
 #define REGISTER_ELEMENT_NOVAL(cname) \
     q=QName(SAMLConstants::SAML1P_NS,cname::LOCAL_NAME); \
@@ -113,8 +113,6 @@ namespace opensaml {
     q=QName(SAMLConstants::SAML1P_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
 
-ValidatorSuite opensaml::saml1p::ProtocolSchemaValidators("ProtocolSchemaValidators");
-
 void opensaml::saml1p::registerProtocolClasses() {
     QName q;
     REGISTER_ELEMENT(AssertionArtifact);
index b5d78ee..a21444d 100644 (file)
@@ -420,11 +420,6 @@ namespace opensaml {
          * Registers builders and validators for SAML 2.0 Assertion classes into the runtime.
          */
         void SAML_API registerAssertionClasses();
-
-        /**
-         * Validator suite for SAML 2.0 Assertion schema validation.
-         */
-        extern SAML_API xmltooling::ValidatorSuite AssertionSchemaValidators;
     };
 };
 
index 02a3d87..2ab5ab4 100644 (file)
@@ -395,11 +395,6 @@ namespace opensaml {
          * Registers builders and validators for SAML 2.0 Protocol classes into the runtime.
          */
         void SAML_API registerProtocolClasses();
-
-        /**
-         * Validator suite for SAML 2.0 Protocol schema validation.
-         */
-        extern SAML_API xmltooling::ValidatorSuite ProtocolSchemaValidators;
     };
 };
 
index 69c9a56..4aaeadf 100644 (file)
@@ -177,12 +177,12 @@ namespace opensaml {
 #define REGISTER_ELEMENT(cname) \
     q=QName(SAMLConstants::SAML20_NS,cname::LOCAL_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    AssertionSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
     
 #define REGISTER_TYPE(cname) \
     q=QName(SAMLConstants::SAML20_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    AssertionSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
 
 #define REGISTER_ELEMENT_NOVAL(cname) \
     q=QName(SAMLConstants::SAML20_NS,cname::LOCAL_NAME); \
@@ -192,8 +192,6 @@ namespace opensaml {
     q=QName(SAMLConstants::SAML20_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
 
-ValidatorSuite opensaml::saml2::AssertionSchemaValidators("AssertionSchemaValidators");
-
 void opensaml::saml2::registerAssertionClasses() {
     QName q;
     REGISTER_ELEMENT(Action);
index d25955f..ceb5d8b 100644 (file)
@@ -224,12 +224,12 @@ namespace opensaml {
 #define REGISTER_ELEMENT(cname) \
     q=QName(SAMLConstants::SAML20P_NS,cname::LOCAL_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    ProtocolSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
     
 #define REGISTER_TYPE(cname) \
     q=QName(SAMLConstants::SAML20P_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    ProtocolSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
 
 #define REGISTER_ELEMENT_NOVAL(cname) \
     q=QName(SAMLConstants::SAML20P_NS,cname::LOCAL_NAME); \
@@ -239,8 +239,6 @@ namespace opensaml {
     q=QName(SAMLConstants::SAML20P_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
 
-ValidatorSuite opensaml::saml2p::ProtocolSchemaValidators("ProtocolSchemaValidators");
-
 void opensaml::saml2p::registerProtocolClasses() {
     QName q;
     REGISTER_ELEMENT(Artifact);
@@ -299,5 +297,5 @@ void opensaml::saml2p::registerProtocolClasses() {
 
     q=QName(SAMLConstants::SAML20P_THIRDPARTY_EXT_NS,RespondTo::LOCAL_NAME);
     XMLObjectBuilder::registerBuilder(q,new RespondToBuilder());
-    ProtocolSchemaValidators.registerValidator(q,new RespondToSchemaValidator());
+    SchemaValidators.registerValidator(q,new RespondToSchemaValidator());
 }
index eee2f66..c8167a2 100644 (file)
@@ -373,7 +373,7 @@ namespace opensaml {
             /** Finds an AuthzDecisionQuery role supporting a given protocol. */
             virtual const AuthzDecisionQueryDescriptorType* getAuthzDecisionQueryDescriptorType(const XMLCh* protocol) const=0;
             /** Finds an extension role supporting a given protocol. */
-            virtual const RoleDescriptor* getRoleDescriptor(xmltooling::QName& qname, const XMLCh* protocol) const=0;
+            virtual const RoleDescriptor* getRoleDescriptor(const xmltooling::QName& qname, const XMLCh* protocol) const=0;
             /** EntityDescriptorType local name */
             static const XMLCh TYPE_NAME[];
         END_XMLOBJECT;
@@ -642,11 +642,6 @@ namespace opensaml {
          * Registers builders and validators for SAML 2.0 Metadata classes into the runtime.
          */
         void SAML_API registerMetadataClasses();
-
-        /**
-         * Validator suite for SAML 2.0 Metadata schema validation.
-         */
-        extern SAML_API xmltooling::ValidatorSuite MetadataSchemaValidators;
     };
 };
 
index f66ebfa..f8eab77 100644 (file)
@@ -2237,7 +2237,36 @@ namespace opensaml {
                 return NULL;
             }
 
-            const RoleDescriptor* getRoleDescriptor(xmltooling::QName& qname, const XMLCh* protocol) const {
+            const RoleDescriptor* getRoleDescriptor(const xmltooling::QName& qname, const XMLCh* protocol) const {
+                // Check for "known" elements/types.
+                QName q;
+                q.setNamespaceURI(SAMLConstants::SAML20MD_NS);
+                q.setLocalPart(IDPSSODescriptor::LOCAL_NAME);
+                if (q == qname)
+                    return getIDPSSODescriptor(protocol);
+                q.setLocalPart(SPSSODescriptor::LOCAL_NAME);
+                if (q == qname)
+                    return getSPSSODescriptor(protocol);
+                q.setLocalPart(AuthnAuthorityDescriptor::LOCAL_NAME);
+                if (q == qname)
+                    return getAuthnAuthorityDescriptor(protocol);
+                q.setLocalPart(AttributeAuthorityDescriptor::LOCAL_NAME);
+                if (q == qname)
+                    return getAttributeAuthorityDescriptor(protocol);
+                q.setLocalPart(PDPDescriptor::LOCAL_NAME);
+                if (q == qname)
+                    return getPDPDescriptor(protocol);
+                q.setNamespaceURI(SAMLConstants::SAML20MD_QUERY_EXT_NS);
+                q.setLocalPart(AuthnQueryDescriptorType::TYPE_NAME);
+                if (q == qname)
+                    return getAuthnQueryDescriptorType(protocol);
+                q.setLocalPart(AttributeQueryDescriptorType::TYPE_NAME);
+                if (q == qname)
+                    return getAttributeQueryDescriptorType(protocol);
+                q.setLocalPart(AuthzDecisionQueryDescriptorType::TYPE_NAME);
+                if (q == qname)
+                    return getAuthzDecisionQueryDescriptorType(protocol);
+                
                 for (vector<RoleDescriptor*>::const_iterator i=m_RoleDescriptors.begin(); i!=m_RoleDescriptors.end(); i++) {
                     if ((*i)->getSchemaType() && qname==(*((*i)->getSchemaType())) && (*i)->hasSupport(protocol) && (*i)->isValid())
                         return (*i);
index 58316f6..36e1a29 100644 (file)
@@ -247,12 +247,12 @@ namespace opensaml {
 #define REGISTER_ELEMENT(cname) \
     q=QName(SAMLConstants::SAML20MD_NS,cname::LOCAL_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    MetadataSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
     
 #define REGISTER_TYPE(cname) \
     q=QName(SAMLConstants::SAML20MD_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder()); \
-    MetadataSchemaValidators.registerValidator(q,new cname##SchemaValidator())
+    SchemaValidators.registerValidator(q,new cname##SchemaValidator())
 
 #define REGISTER_ELEMENT_NOVAL(cname) \
     q=QName(SAMLConstants::SAML20MD_NS,cname::LOCAL_NAME); \
@@ -262,8 +262,6 @@ namespace opensaml {
     q=QName(SAMLConstants::SAML20MD_NS,cname::TYPE_NAME); \
     XMLObjectBuilder::registerBuilder(q,new cname##Builder());
 
-ValidatorSuite opensaml::saml2md::MetadataSchemaValidators("MetadataSchemaValidators");
-
 void opensaml::saml2md::registerMetadataClasses() {
     QName q;
     REGISTER_ELEMENT(AdditionalMetadataLocation);
@@ -326,21 +324,21 @@ void opensaml::saml2md::registerMetadataClasses() {
 
     q=QName(SAMLConstants::SAML1MD_NS,SourceID::LOCAL_NAME);
     XMLObjectBuilder::registerBuilder(q,new SourceIDBuilder());
-    MetadataSchemaValidators.registerValidator(q,new SourceIDSchemaValidator());
+    SchemaValidators.registerValidator(q,new SourceIDSchemaValidator());
 
     q=QName(SAMLConstants::SAML20MD_QUERY_EXT_NS,ActionNamespace::LOCAL_NAME);
     XMLObjectBuilder::registerBuilder(q,new ActionNamespaceBuilder());
-    MetadataSchemaValidators.registerValidator(q,new ActionNamespaceSchemaValidator());
+    SchemaValidators.registerValidator(q,new ActionNamespaceSchemaValidator());
 
     q=QName(SAMLConstants::SAML20MD_QUERY_EXT_NS,AuthnQueryDescriptorType::TYPE_NAME);
     XMLObjectBuilder::registerBuilder(q,new AuthnQueryDescriptorTypeBuilder());
-    MetadataSchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
+    SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
 
     q=QName(SAMLConstants::SAML20MD_QUERY_EXT_NS,AttributeQueryDescriptorType::TYPE_NAME);
     XMLObjectBuilder::registerBuilder(q,new AttributeQueryDescriptorTypeBuilder());
-    MetadataSchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
+    SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
 
     q=QName(SAMLConstants::SAML20MD_QUERY_EXT_NS,AuthzDecisionQueryDescriptorType::TYPE_NAME);
     XMLObjectBuilder::registerBuilder(q,new AuthzDecisionQueryDescriptorTypeBuilder());
-    MetadataSchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
+    SchemaValidators.registerValidator(q,new RoleDescriptorSchemaValidator());
 }