From 5263186a620ca02913980ad2d35d4045844e7a05 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 2 Oct 2006 05:22:30 +0000 Subject: [PATCH] ReplayCache, some decoder work, and merged schema validators into one suite. --- saml/Makefile.am | 6 + saml/SAMLConfig.cpp | 120 +++++++++- saml/SAMLConfig.h | 28 ++- saml/binding/MessageDecoder.h | 249 +++++++++++++++++++++ saml/binding/MessageEncoder.h | 3 +- saml/binding/ReplayCache.h | 67 ++++++ saml/binding/impl/MessageDecoder.cpp | 48 ++++ saml/binding/impl/ReplayCache.cpp | 48 ++++ saml/exceptions.h | 44 ++++ saml/saml.vcproj | 24 ++ saml/saml1/binding/SAML1POSTDecoder.h | 51 +++++ saml/saml1/binding/impl/SAML1POSTDecoder.cpp | 183 +++++++++++++++ saml/saml1/core/Assertions.h | 5 - saml/saml1/core/Protocols.h | 5 - .../saml1/core/impl/AssertionsSchemaValidators.cpp | 6 +- saml/saml1/core/impl/ProtocolsSchemaValidators.cpp | 6 +- saml/saml2/core/Assertions.h | 5 - saml/saml2/core/Protocols.h | 5 - .../core/impl/Assertions20SchemaValidators.cpp | 6 +- .../core/impl/Protocols20SchemaValidators.cpp | 8 +- saml/saml2/metadata/Metadata.h | 7 +- saml/saml2/metadata/impl/MetadataImpl.cpp | 31 ++- .../metadata/impl/MetadataSchemaValidators.cpp | 16 +- 23 files changed, 904 insertions(+), 67 deletions(-) create mode 100644 saml/binding/MessageDecoder.h create mode 100644 saml/binding/ReplayCache.h create mode 100644 saml/binding/impl/MessageDecoder.cpp create mode 100644 saml/binding/impl/ReplayCache.cpp create mode 100644 saml/saml1/binding/SAML1POSTDecoder.h create mode 100644 saml/saml1/binding/impl/SAML1POSTDecoder.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index cc3ee2d..d0ebc77 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -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 \ diff --git a/saml/SAMLConfig.cpp b/saml/SAMLConfig.cpp index 5d68230..4e4c7ce 100644 --- a/saml/SAMLConfig.cpp +++ b/saml/SAMLConfig.cpp @@ -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& roles=entity->getOrderedChildren(); + for (list::const_iterator child=roles.begin(); child!=roles.end(); ++child) { + const RoleDescriptor* role=dynamic_cast(*child); + if (role && role->isValid()) { + const vector& contacts=role->getContactPersons(); + for (vector::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& emails=const_cast(*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(role->getParent())->getEntityID()); + e->addProperty("entityID",id.get()); + + const vector& contacts=role->getContactPersons(); + for (vector::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& emails=const_cast(*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(); +} diff --git a/saml/SAMLConfig.h b/saml/SAMLConfig.h index 1d0dbd1..8491d0f 100644 --- a/saml/SAMLConfig.h +++ b/saml/SAMLConfig.h @@ -39,6 +39,7 @@ namespace opensaml { class SAML_API ArtifactMap; class SAML_API MessageEncoder; class SAML_API MessageDecoder; + class SAML_API ReplayCache; class SAML_API SAMLArtifact; class SAML_API TrustEngine; class SAML_API URLEncoder; @@ -106,7 +107,7 @@ namespace opensaml { /** * Returns the global ArtifactMap instance. * - * @return global ArtifactMap + * @return global ArtifactMap or NULL */ ArtifactMap* getArtifactMap() const { return m_artifactMap; @@ -124,13 +125,31 @@ namespace opensaml { /** * Returns the global URLEncoder instance. * - * @return global URLEncoder + * @return global URLEncoder or NULL */ URLEncoder* getURLEncoder() const { return m_urlEncoder; } /** + * Sets the global ReplayCache instance. + * This method must be externally synchronized with any code that uses the object. + * Any previously set object is destroyed. + * + * @param replayCache new ReplayCache instance to store + */ + void setReplayCache(ReplayCache* replayCache); + + /** + * Returns the global ReplayCache instance. + * + * @return global ReplayCache or NULL + */ + ReplayCache* getReplayCache() const { + return m_replayCache; + } + + /** * Generate random information using the underlying security library * * @param buf buffer for the information @@ -195,13 +214,16 @@ namespace opensaml { xmltooling::PluginManager MetadataFilterManager; protected: - SAMLConfig() : m_artifactMap(NULL), m_urlEncoder(NULL) {} + SAMLConfig() : m_artifactMap(NULL), m_urlEncoder(NULL), m_replayCache(NULL) {} /** Global ArtifactMap instance for use by artifact-related functions. */ ArtifactMap* m_artifactMap; /** Global URLEncoder instance for use by URL-related functions. */ URLEncoder* m_urlEncoder; + + /** Global ReplayCache instance. */ + ReplayCache* m_replayCache; }; #if defined (_MSC_VER) diff --git a/saml/binding/MessageDecoder.h b/saml/binding/MessageDecoder.h new file mode 100644 index 0000000..609273f --- /dev/null +++ b/saml/binding/MessageDecoder.h @@ -0,0 +1,249 @@ +/* + * 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/binding/MessageDecoder.h + * + * Interface to SAML protocol binding message decoders. + */ + +#ifndef __saml_decoder_h__ +#define __saml_decoder_h__ + +#include + +#include + +namespace opensaml { + + class SAML_API SAMLArtifact; + class SAML_API X509TrustEngine; + namespace saml1p { + class SAML_API Response; + }; + namespace saml2p { + class SAML_API SAML2Artifact; + }; + namespace saml2md { + class SAML_API MetadataProvider; + class SAML_API IDPSSODescriptor; + class SAML_API RoleDescriptor; + class SAML_API SSODescriptorType; + } + + /** + * Interface to SAML protocol binding message decoders. + */ + class SAML_API MessageDecoder + { + MAKE_NONCOPYABLE(MessageDecoder); + public: + virtual ~MessageDecoder() {} + + /** + * Interface to caller-supplied shim for accessing HTTP request context. + * + * To supply information from the surrounding web server environment, + * a shim must be supplied in the form of this interface to adapt the + * library to different proprietary server APIs. + */ + class SAML_API HTTPRequest { + MAKE_NONCOPYABLE(HTTPRequest); + protected: + HTTPRequest() {} + public: + virtual ~HTTPRequest() {} + + /** + * Returns the HTTP method of the request (GET, POST, etc.) + * + * @return the HTTP method + */ + virtual const char* getMethod() const=0; + + /** + * Returns the complete request URL, including scheme, host, port. + * + * @return the request URL + */ + virtual const char* getRequestURL() const=0; + + /** + * Returns the HTTP query string appened to the request. The query + * string is returned without any decoding applied, everything found + * after the ? delimiter. + * + * @return the query string + */ + virtual const char* getQueryString() const=0; + + /** + * Returns a decoded named parameter value from the query string or form body. + * If a parameter has multiple values, only one will be returned. + * + * @param name the name of the parameter to return + * @return a single parameter value or NULL + */ + virtual const char* getParameter(const char* name) const=0; + + /** + * Returns all of the decoded values of a named parameter from the query string + * or form body. All values found will be returned. + * + * @param name the name of the parameter to return + * @param values a vector in which to return pointers to the decoded values + * @return the number of values returned + */ + virtual std::vector::size_type getParameters( + const char* name, std::vector& values + ) const=0; + }; + + /** + * Interface to caller-supplied artifact resolution mechanism. + * + * Resolving artifacts requires internally performing a SOAP-based + * call to the artifact source, usually in a mutually authenticated fashion. + * The potential options vary widely, so the work is encapsulated by this + * interface, though of course other library facilities may be used. + * + *

A MessageDecoder implementation will invoke the supplied interface + * when it requires an artifact be resolved. + */ + class SAML_API ArtifactResolver { + MAKE_NONCOPYABLE(ArtifactResolver); + protected: + ArtifactResolver() {} + public: + virtual ~ArtifactResolver() {} + + /** + * Resolves one or more SAML 1.x artifacts into a response containing a set of + * resolved Assertions. The caller is responsible for the resulting Response. + * + * @param artifacts one or more SAML 1.x artifacts + * @param idpDescriptor reference to IdP role of artifact issuer + * @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder + * @return the corresponding SAML Assertions wrapped in a Response. + */ + virtual saml1p::Response* resolve( + const std::vector& artifacts, + const saml2md::IDPSSODescriptor& idpDescriptor, + const X509TrustEngine* trustEngine=NULL + ) const=0; + + /** + * Resolves a SAML 2.0 artifact into the corresponding SAML protocol message. + * The caller is responsible for the resulting XMLObject. + * + * @param artifact reference to a SAML 2.0 artifact + * @param ssoDescriptor reference to SSO role of artifact issuer (may be SP or IdP) + * @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder + * @return the corresponding SAML protocol message or NULL + */ + virtual xmltooling::XMLObject* resolve( + const saml2p::SAML2Artifact& artifact, + const saml2md::SSODescriptorType& ssoDescriptor, + const X509TrustEngine* trustEngine=NULL + ) const=0; + }; + + /** + * Provides an ArtifactResolver implementation for the MessageDecoder to use. + * The implementation's lifetime must be longer than the lifetime of this object. + * This method must be externally synchronized. + * + * @param artifactResolver an ArtifactResolver implementation to use + */ + void setArtifactResolver(ArtifactResolver* artifactResolver) { + m_artifactResolver = artifactResolver; + } + + /** + * Controls schema validation of incoming XML messages. + * This is separate from other forms of programmatic validation of objects, + * but can detect a much wider range of syntax errors. + * + * @param validate true iff the decoder should use a validating XML parser + */ + void setValidating(bool validate=true) { + m_validate = validate; + } + + /** + * Decodes an HTTP request into a SAML protocol message, and returns related + * information about the issuer of the message and whether it can be trusted. + * If the HTTP request does not contain the information necessary to decode + * the request, a NULL will be returned. Errors during the decoding process + * will be raised as exceptions. + * + *

Artifact-based bindings require an ArtifactResolver be set to + * turn an artifact into the corresponding message. + * + *

In some cases, a message may be returned but not authenticated. The caller + * should examine the issuerTrusted output value to establish this. + * + * @param relayState RelayState/TARGET value accompanying message + * @param issuer role descriptor of issuing party + * @param issuerTrusted will be true iff the message was authenticated (signed or obtained via secure backchannel) + * @param httpRequest reference to interface for accessing HTTP message to decode + * @param metadataProvider optional MetadataProvider instance to authenticate the message + * @param role optional, identifies the role (generally IdP or SP) of the peer who issued the message + * @param trustEngine optional X509TrustEngine to authenticate the message + * @return the decoded message, or NULL if the decoder did not recognize the request content + */ + virtual xmltooling::XMLObject* 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=0; + + protected: + MessageDecoder() : m_artifactResolver(NULL), m_validate(false) {} + + /** Pointer to an ArtifactResolver implementation. */ + const ArtifactResolver* m_artifactResolver; + + /** Flag controlling schema validation. */ + bool m_validate; + }; + + /** + * Registers MessageDecoder plugins into the runtime. + */ + void SAML_API registerMessageDecoders(); + + /** MessageDecoder for SAML 1.x Browser/Artifact "binding" (really part of profile) */ + #define SAML1_ARTIFACT_DECODER "urn:oasis:names:tc:SAML:1.0:profiles:artifact-01" + + /** MessageDecoder for SAML 1.x Browser/POST "binding" (really part of profile) */ + #define SAML1_POST_DECODER "urn:oasis:names:tc:SAML:1.0:profiles:browser-post" + + /** MessageDecoder for SAML 2.0 HTTP-Artifact binding */ + #define SAML2_ARTIFACT_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" + + /** MessageDecoder for SAML 2.0 HTTP-POST binding */ + #define SAML2_POST_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" + + /** MessageDecoder for SAML 2.0 HTTP-Redirect binding */ + #define SAML2_REDIRECT_DECODER "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" +}; + +#endif /* __saml_decoder_h__ */ diff --git a/saml/binding/MessageEncoder.h b/saml/binding/MessageEncoder.h index 2a5fc71..acfdf15 100644 --- a/saml/binding/MessageEncoder.h +++ b/saml/binding/MessageEncoder.h @@ -29,7 +29,6 @@ #include #include #include -#include namespace opensaml { @@ -54,7 +53,7 @@ namespace opensaml { * the sender's SourceID (or sometimes SourceLocation), and the relying party's * preferred artifact type. This information can be supplied using whatever * configuration or defaults are appropriate for the SAML application. - * An ArtifactMap implementation will invoke the supplied generator interface + * A MessageEncoder implementation will invoke the supplied generator interface * when it requires an artifact be created. */ class SAML_API ArtifactGenerator { diff --git a/saml/binding/ReplayCache.h b/saml/binding/ReplayCache.h new file mode 100644 index 0000000..d5655fd --- /dev/null +++ b/saml/binding/ReplayCache.h @@ -0,0 +1,67 @@ +/* + * 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/binding/ReplayCache.h + * + * Helper class on top of StorageService for detecting message replay. + */ + +#ifndef __saml_replay_h__ +#define __saml_replay_h__ + +#include +#include + +namespace opensaml { + + /** + * Helper class on top of StorageService for detecting message replay. + */ + class SAML_API ReplayCache + { + MAKE_NONCOPYABLE(ReplayCache); + public: + + /** + * Creates a replay cache on top of a particular StorageService. + * + * @param storage pointer to a StorageService, or NULL to keep cache in memory + */ + ReplayCache(xmltooling::StorageService* storage=NULL); + + virtual ~ReplayCache(); + + /** + * Returns true iff the check value is not found in the cache, and stores it. + * + * @param context a context label to subdivide the cache + * @param s value to check + * @param expires time for disposal of value from cache + */ + virtual bool check(const char* context, const char* s, time_t expires); + + bool check(const char* context, const XMLCh* str, time_t expires) { + xmltooling::auto_ptr_char temp(str); + return check(context, temp.get(), expires); + } + + private: + xmltooling::StorageService* m_storage; + }; +}; + +#endif /* __saml_replay_h__ */ diff --git a/saml/binding/impl/MessageDecoder.cpp b/saml/binding/impl/MessageDecoder.cpp new file mode 100644 index 0000000..0b87270 --- /dev/null +++ b/saml/binding/impl/MessageDecoder.cpp @@ -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::Factory SAML1ArtifactDecoderFactory; + SAML_DLLLOCAL PluginManager::Factory SAML1POSTDecoderFactory; + }; + + namespace saml2p { + SAML_DLLLOCAL PluginManager::Factory SAML2ArtifactDecoderFactory; + SAML_DLLLOCAL PluginManager::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 index 0000000..5081bce --- /dev/null +++ b/saml/binding/impl/ReplayCache.cpp @@ -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; +} diff --git a/saml/exceptions.h b/saml/exceptions.h index 186aa4e..b44102e 100644 --- a/saml/exceptions.h +++ b/saml/exceptions.h @@ -27,7 +27,51 @@ #include 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: + * + *

+ *
providerId
The unique ID of the entity
+ *
errorURL
The error support URL of a random role
+ *
contactName
A formatted support or technical contact name
+ *
contactEmail
A contact email address
+ *
+ * + * @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: + * + *
+ *
providerId
The unique ID of the entity
+ *
errorURL
The error support URL of the role
+ *
contactName
A formatted support or technical contact name
+ *
contactEmail
A contact email address
+ *
+ * + * @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__ */ diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 4a8d469..cbfd019 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -239,6 +239,10 @@ > + + @@ -444,10 +448,18 @@ > + + + + @@ -518,6 +530,10 @@ > + + @@ -651,10 +667,18 @@ > + + + + diff --git a/saml/saml1/binding/SAML1POSTDecoder.h b/saml/saml1/binding/SAML1POSTDecoder.h new file mode 100644 index 0000000..464a17b --- /dev/null +++ b/saml/saml1/binding/SAML1POSTDecoder.h @@ -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 +#include + + +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 index 0000000..b99ab68 --- /dev/null +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -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 +#include +#include + +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(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(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 janitor(doc); + auto_ptr xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true)); + janitor.release(); + + Response* response = dynamic_cast(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& assertions=const_cast(response)->getAssertions(); + if (!assertions.empty()) { + const EntityDescriptor* provider= + metadataProvider ? metadataProvider->getEntityDescriptor(assertions.front()->getIssuer()) : NULL; + if (provider) { + pair 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(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& assertions=const_cast(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 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; +} diff --git a/saml/saml1/core/Assertions.h b/saml/saml1/core/Assertions.h index a8fe0fe..53843d0 100644 --- a/saml/saml1/core/Assertions.h +++ b/saml/saml1/core/Assertions.h @@ -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; }; }; diff --git a/saml/saml1/core/Protocols.h b/saml/saml1/core/Protocols.h index c3300b9..e30ff19 100644 --- a/saml/saml1/core/Protocols.h +++ b/saml/saml1/core/Protocols.h @@ -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; }; }; diff --git a/saml/saml1/core/impl/AssertionsSchemaValidators.cpp b/saml/saml1/core/impl/AssertionsSchemaValidators.cpp index df178bd..72a6143 100644 --- a/saml/saml1/core/impl/AssertionsSchemaValidators.cpp +++ b/saml/saml1/core/impl/AssertionsSchemaValidators.cpp @@ -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); diff --git a/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp b/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp index c52e988..445ec2b 100644 --- a/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp +++ b/saml/saml1/core/impl/ProtocolsSchemaValidators.cpp @@ -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); diff --git a/saml/saml2/core/Assertions.h b/saml/saml2/core/Assertions.h index b5d78ee..a21444d 100644 --- a/saml/saml2/core/Assertions.h +++ b/saml/saml2/core/Assertions.h @@ -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; }; }; diff --git a/saml/saml2/core/Protocols.h b/saml/saml2/core/Protocols.h index 02a3d87..2ab5ab4 100644 --- a/saml/saml2/core/Protocols.h +++ b/saml/saml2/core/Protocols.h @@ -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; }; }; diff --git a/saml/saml2/core/impl/Assertions20SchemaValidators.cpp b/saml/saml2/core/impl/Assertions20SchemaValidators.cpp index 69c9a56..4aaeadf 100644 --- a/saml/saml2/core/impl/Assertions20SchemaValidators.cpp +++ b/saml/saml2/core/impl/Assertions20SchemaValidators.cpp @@ -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); diff --git a/saml/saml2/core/impl/Protocols20SchemaValidators.cpp b/saml/saml2/core/impl/Protocols20SchemaValidators.cpp index d25955f..ceb5d8b 100644 --- a/saml/saml2/core/impl/Protocols20SchemaValidators.cpp +++ b/saml/saml2/core/impl/Protocols20SchemaValidators.cpp @@ -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()); } diff --git a/saml/saml2/metadata/Metadata.h b/saml/saml2/metadata/Metadata.h index eee2f66..c8167a2 100644 --- a/saml/saml2/metadata/Metadata.h +++ b/saml/saml2/metadata/Metadata.h @@ -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; }; }; diff --git a/saml/saml2/metadata/impl/MetadataImpl.cpp b/saml/saml2/metadata/impl/MetadataImpl.cpp index f66ebfa..f8eab77 100644 --- a/saml/saml2/metadata/impl/MetadataImpl.cpp +++ b/saml/saml2/metadata/impl/MetadataImpl.cpp @@ -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::const_iterator i=m_RoleDescriptors.begin(); i!=m_RoleDescriptors.end(); i++) { if ((*i)->getSchemaType() && qname==(*((*i)->getSchemaType())) && (*i)->hasSupport(protocol) && (*i)->isValid()) return (*i); diff --git a/saml/saml2/metadata/impl/MetadataSchemaValidators.cpp b/saml/saml2/metadata/impl/MetadataSchemaValidators.cpp index 58316f6..36e1a29 100644 --- a/saml/saml2/metadata/impl/MetadataSchemaValidators.cpp +++ b/saml/saml2/metadata/impl/MetadataSchemaValidators.cpp @@ -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()); } -- 2.1.4