From dcfc67313c4b048f6f67636be1627f4ef13970a8 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 8 Nov 2007 20:52:06 +0000 Subject: [PATCH] Add option to search all providers and warn on duplicates. --- saml/saml2/metadata/ChainingMetadataProvider.h | 3 + .../metadata/impl/ChainingMetadataProvider.cpp | 150 ++++++++++++++++++--- 2 files changed, 134 insertions(+), 19 deletions(-) diff --git a/saml/saml2/metadata/ChainingMetadataProvider.h b/saml/saml2/metadata/ChainingMetadataProvider.h index 2e24646..1310374 100644 --- a/saml/saml2/metadata/ChainingMetadataProvider.h +++ b/saml/saml2/metadata/ChainingMetadataProvider.h @@ -24,6 +24,7 @@ #define __saml_chainmeta_h__ #include +#include #include namespace opensaml { @@ -103,8 +104,10 @@ namespace opensaml { ) const; private: + bool m_firstMatch; xmltooling::ThreadKey* m_tlsKey; std::vector m_providers; + xmltooling::logging::Category& m_log; }; #if defined (_MSC_VER) diff --git a/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp index 9f90400..f1e0a09 100644 --- a/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp @@ -22,6 +22,7 @@ #include "internal.h" #include "exceptions.h" +#include "saml/binding/SAMLArtifact.h" #include "saml2/metadata/ChainingMetadataProvider.h" #include @@ -46,17 +47,22 @@ namespace opensaml { }; static const XMLCh _MetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r); +static const XMLCh precedence[] = UNICODE_LITERAL_10(p,r,e,c,e,d,e,n,c,e); +static const XMLCh last[] = UNICODE_LITERAL_4(l,a,s,t); static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); -ChainingMetadataProvider::ChainingMetadataProvider(const DOMElement* e) : ObservableMetadataProvider(e), m_tlsKey(NULL) +ChainingMetadataProvider::ChainingMetadataProvider(const DOMElement* e) + : ObservableMetadataProvider(e), m_firstMatch(true), m_tlsKey(NULL), m_log(Category::getInstance(SAML_LOGCAT".Metadata.Chaining")) { - Category& log=Category::getInstance(SAML_LOGCAT".Metadata.Chaining"); + if (XMLString::equals(e ? e->getAttributeNS(NULL, precedence) : NULL, last)) + m_firstMatch = false; + e = e ? XMLHelper::getFirstChildElement(e, _MetadataProvider) : NULL; while (e) { auto_ptr_char temp(e->getAttributeNS(NULL,type)); if (temp.get() && *temp.get()) { try { - log.info("building MetadataProvider of type %s", temp.get()); + m_log.info("building MetadataProvider of type %s", temp.get()); auto_ptr provider( SAMLConfig::getConfig().MetadataProviderManager.newPlugin(temp.get(), e) ); @@ -67,7 +73,7 @@ ChainingMetadataProvider::ChainingMetadataProvider(const DOMElement* e) : Observ provider.release(); } catch (exception& ex) { - log.error("error building MetadataProvider: %s", ex.what()); + m_log.error("error building MetadataProvider: %s", ex.what()); } } e = XMLHelper::getNextSiblingElement(e, _MetadataProvider); @@ -93,7 +99,7 @@ void ChainingMetadataProvider::init() (*i)->init(); } catch (exception& ex) { - Category::getInstance(SAML_LOGCAT".Metadata").error("failure initializing MetadataProvider: %s", ex.what()); + m_log.error("failure initializing MetadataProvider: %s", ex.what()); } } } @@ -124,39 +130,145 @@ const EntitiesDescriptor* ChainingMetadataProvider::getEntitiesDescriptor(const const_cast(this)->unlock(); // Do a search. + MetadataProvider* held = NULL; const EntitiesDescriptor* ret=NULL; + const EntitiesDescriptor* cur=NULL; for (vector::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) { (*i)->lock(); - if (ret=(*i)->getEntitiesDescriptor(name,requireValidMetadata)) { - // Save locked provider. - m_tlsKey->setData(*i); - return ret; + if (cur=(*i)->getEntitiesDescriptor(name,requireValidMetadata)) { + // Are we using a first match policy? + if (m_firstMatch) { + // Save locked provider. + m_tlsKey->setData(*i); + return cur; + } + + // Using last match wins. Did we already have one? + if (held) { + m_log.warn("found duplicate EntitiesDescriptor (%s), using last matching copy", name); + held->unlock(); + } + + // Save off the latest match. + held = *i; + ret = cur; + } + else { + // No match, so just unlock this one and move on. + (*i)->unlock(); } - (*i)->unlock(); } - return NULL; + // Preserve any lock we're holding. + if (held) + m_tlsKey->setData(held); + return ret; } pair ChainingMetadataProvider::getEntityDescriptor(const Criteria& criteria) const { + bool bRole = (criteria.role && criteria.protocol); // searching for role also? + // Clear any existing lock. const_cast(this)->unlock(); // Do a search. - pair ret; - ret.first = NULL; - ret.second = NULL; + MetadataProvider* held = NULL; + pair ret = pair(NULL,NULL); + pair cur = ret; for (vector::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) { (*i)->lock(); - if ((ret=(*i)->getEntityDescriptor(criteria)).first) { - // Save locked provider. - m_tlsKey->setData(*i); - return ret; + cur = (*i)->getEntityDescriptor(criteria); + if (cur.first) { + if (bRole) { + // We want a role also. Did we find one? + if (cur.second) { + // Are we using a first match policy? + if (m_firstMatch) { + // Save locked provider. + m_tlsKey->setData(*i); + return cur; + } + + // Using last match wins. Did we already have one? + if (held) { + if (ret.second) { + // We had a "complete" match, so log it. + if (criteria.entityID_ascii) { + m_log.warn("found duplicate EntityDescriptor (%s) with role (%s), using last matching copy", + criteria.entityID_ascii, criteria.role->toString().c_str()); + } + else if (criteria.entityID_unicode) { + auto_ptr_char temp(criteria.entityID_unicode); + m_log.warn("found duplicate EntityDescriptor (%s) with role (%s), using last matching copy", + temp.get(), criteria.role->toString().c_str()); + } + else if (criteria.artifact) { + m_log.warn("found duplicate EntityDescriptor for artifact source (%s) with role (%s), using last matching copy", + criteria.artifact->getSource().c_str(), criteria.role->toString().c_str()); + } + } + held->unlock(); + } + + // Save off the latest match. + held = *i; + ret = cur; + } + else { + // We didn't find the role, so we're going to keep looking, + // but save this one if we didn't have the role yet. + if (ret.second) { + // We already had a role, so let's stick with that. + (*i)->unlock(); + } + else { + // This is at least as good, so toss anything we had and keep it. + if (held) + held->unlock(); + held = *i; + ret = cur; + } + } + } + else { + // Are we using a first match policy? + if (m_firstMatch) { + // Save locked provider. + m_tlsKey->setData(*i); + return cur; + } + + // Using last match wins. Did we already have one? + if (held) { + if (criteria.entityID_ascii) { + m_log.warn("found duplicate EntityDescriptor (%s), using last matching copy", criteria.entityID_ascii); + } + else if (criteria.entityID_unicode) { + auto_ptr_char temp(criteria.entityID_unicode); + m_log.warn("found duplicate EntityDescriptor (%s), using last matching copy", temp.get()); + } + else if (criteria.artifact) { + m_log.warn("found duplicate EntityDescriptor for artifact source (%s), using last matching copy", + criteria.artifact->getSource().c_str()); + } + held->unlock(); + } + + // Save off the latest match. + held = *i; + ret = cur; + } + } + else { + // No match, so just unlock this one and move on. + (*i)->unlock(); } - (*i)->unlock(); } + // Preserve any lock we're holding. + if (held) + m_tlsKey->setData(held); return ret; } -- 2.1.4