From 4a6e7f38d8e33c6a9bb02cb96a952f130c82968e Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 11 Sep 2006 02:08:40 +0000 Subject: [PATCH] Added abstract metadata base, chaining trust and metadata plugins. --- saml/Makefile.am | 8 +- saml/saml.vcproj | 24 +++ saml/saml2/metadata/AbstractMetadataProvider.h | 108 ++++++++++++ saml/saml2/metadata/ChainingMetadataProvider.h | 101 +++++++++++ saml/saml2/metadata/MetadataProvider.h | 46 +---- saml/saml2/metadata/ObservableMetadataProvider.h | 4 +- .../metadata/impl/AbstractMetadataProvider.cpp | 190 +++++++++++++++++++++ .../metadata/impl/ChainingMetadataProvider.cpp | 176 +++++++++++++++++++ .../metadata/impl/FilesystemMetadataProvider.cpp | 10 +- saml/saml2/metadata/impl/MetadataProvider.cpp | 155 +---------------- .../metadata/impl/ObservableMetadataProvider.cpp | 6 - saml/security/ChainingTrustEngine.h | 99 +++++++++++ saml/security/TrustEngine.h | 3 + saml/security/impl/ChainingTrustEngine.cpp | 99 +++++++++++ saml/security/impl/TrustEngine.cpp | 2 + 15 files changed, 832 insertions(+), 199 deletions(-) create mode 100644 saml/saml2/metadata/AbstractMetadataProvider.h create mode 100644 saml/saml2/metadata/ChainingMetadataProvider.h create mode 100644 saml/saml2/metadata/impl/AbstractMetadataProvider.cpp create mode 100644 saml/saml2/metadata/impl/ChainingMetadataProvider.cpp create mode 100644 saml/security/ChainingTrustEngine.h create mode 100644 saml/security/impl/ChainingTrustEngine.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index f46e7c0..91cd7ce 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -31,6 +31,7 @@ encinclude_HEADERS = \ secinclude_HEADERS = \ security/AbstractPKIXTrustEngine.h \ security/MetadataKeyInfoIterator.h \ + security/ChainingTrustEngine.h \ security/TrustEngine.h \ security/X509TrustEngine.h @@ -55,7 +56,9 @@ saml2coreinclude_HEADERS = \ saml2/core/SAML2ArtifactType0004.h saml2mdinclude_HEADERS = \ - saml2/metadata/Metadata.h + saml2/metadata/AbstractMetadataProvider.h \ + saml2/metadata/ChainingMetadataProvider.h \ + saml2/metadata/Metadata.h \ saml2/metadata/MetadataFilter.h \ saml2/metadata/MetadataProvider.h \ saml2/metadata/ObservableMetadataProvider.h @@ -78,7 +81,9 @@ libsaml_la_SOURCES = \ saml2/core/impl/Protocols20SchemaValidators.cpp \ saml2/core/impl/SAML2Artifact.cpp \ saml2/core/impl/SAML2ArtifactType0004.cpp \ + saml2/metadata/impl/AbstractMetadataProvider.cpp \ saml2/metadata/impl/BlacklistMetadataFilter.cpp \ + saml2/metadata/impl/ChainingMetadataProvider.cpp \ saml2/metadata/impl/FilesystemMetadataProvider.cpp \ saml2/metadata/impl/MetadataImpl.cpp \ saml2/metadata/impl/MetadataProvider.cpp \ @@ -89,6 +94,7 @@ libsaml_la_SOURCES = \ encryption/EncryptedKeyResolver.cpp \ security/impl/TrustEngine.cpp \ security/impl/AbstractPKIXTrustEngine.cpp \ + security/impl/ChainingTrustEngine.cpp \ security/impl/ExplicitKeyTrustEngine.cpp \ signature/ContentReference.cpp \ signature/SignatureProfileValidator.cpp \ diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 27b7e03..40d6d78 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -303,10 +303,18 @@ Name="impl" > + + + + @@ -364,6 +372,10 @@ > + + @@ -486,6 +498,14 @@ Name="metadata" > + + + + @@ -523,6 +543,10 @@ > + + diff --git a/saml/saml2/metadata/AbstractMetadataProvider.h b/saml/saml2/metadata/AbstractMetadataProvider.h new file mode 100644 index 0000000..16d121b --- /dev/null +++ b/saml/saml2/metadata/AbstractMetadataProvider.h @@ -0,0 +1,108 @@ +/* + * 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/saml2/metadata/AbstractMetadataProvider.h + * + * Base class for caching metadata providers. + */ + +#ifndef __saml2_absmetadataprov_h__ +#define __saml2_absmetadataprov_h__ + +#include + +namespace opensaml { + + namespace saml2md { + + /** + * Base class for caching metadata providers. + */ + class SAML_API AbstractMetadataProvider : public ObservableMetadataProvider + { + protected: + /** + * Constructor. + * + * If a DOM is supplied, a set of default logic will be used to identify + * and build a KeyResolver plugin and install it into the provider. + * + * The following XML content is supported: + * + * + * + * XML namespaces are ignored in the processing of these elements. + * + * @param e DOM to supply configuration for provider + */ + AbstractMetadataProvider(const DOMElement* e=NULL); + + void emitChangeEvent(); + + public: + virtual ~AbstractMetadataProvider(); + + virtual const xmlsignature::KeyResolver* getKeyResolver() const { + return m_resolver; + } + + virtual const EntityDescriptor* getEntityDescriptor(const char* id, bool requireValidMetadata=true) const; + virtual const EntityDescriptor* getEntityDescriptor(const SAMLArtifact* artifact) const; + virtual const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const; + + protected: + /** Embedded KeyResolver instance. */ + xmlsignature::KeyResolver* m_resolver; + + /** + * Loads an entity into the cache for faster lookup. This includes + * processing known reverse lookup strategies for artifacts. + * + * @param site entity definition + * @param validUntil expiration time of the entity definition + */ + virtual void index(EntityDescriptor* site, time_t validUntil); + + /** + * Loads a group of entities into the cache for faster lookup. + * + * @param group group definition + * @param validUntil expiration time of the group definition + */ + virtual void index(EntitiesDescriptor* group, time_t validUntil); + + /** + * Clear the cache of known entities and groups. + */ + virtual void clearDescriptorIndex(); + + private: + std::vector m_filters; + + typedef std::multimap sitemap_t; + typedef std::multimap groupmap_t; + sitemap_t m_sites; + sitemap_t m_sources; + groupmap_t m_groups; + }; + + }; +}; + +#endif /* __saml2_absmetadataprov_h__ */ diff --git a/saml/saml2/metadata/ChainingMetadataProvider.h b/saml/saml2/metadata/ChainingMetadataProvider.h new file mode 100644 index 0000000..d71a254 --- /dev/null +++ b/saml/saml2/metadata/ChainingMetadataProvider.h @@ -0,0 +1,101 @@ +/* + * 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/security/ChainingMetadataProvider.h + * + * MetadataProvider that uses multiple providers in sequence. + */ + +#ifndef __saml_chainmeta_h__ +#define __saml_chainmeta_h__ + +#include +#include + +namespace opensaml { + namespace saml2md { + + /** + * MetadataProvider that uses multiple providers in sequence. + */ + class SAML_API ChainingMetadataProvider + : public ObservableMetadataProvider, public ObservableMetadataProvider::Observer { + public: + /** + * Constructor. + * + * If a DOM is supplied, the following XML content is supported: + * + *
    + *
  • <MetadataProvider> elements with a type attribute + *
+ * + * XML namespaces are ignored in the processing of this content. + * + * @param e DOM to supply configuration for provider + */ + ChainingMetadataProvider(const DOMElement* e=NULL); + + /** + * Destructor will delete any embedded engines. + */ + virtual ~ChainingMetadataProvider(); + + /** + * Adds a provider for future calls. The provider MUST be + * initialized before adding it. + * + * @param newProvider provider to add + */ + void addMetadataProvider(MetadataProvider* newProvider) { + m_providers.push_back(newProvider); + } + + /** + * Removes a provider. The caller must delete the provider if necessary. + * + * @param oldProvider provider to remove + * @return the old provider + */ + MetadataProvider* removeMetadataProvider(MetadataProvider* oldProvider) { + for (std::vector::iterator i=m_providers.begin(); i!=m_providers.end(); i++) { + if (oldProvider==(*i)) { + m_providers.erase(i); + return oldProvider; + } + } + return NULL; + } + + xmltooling::Lockable* lock(); + void unlock(); + void init(); + const xmlsignature::KeyResolver* getKeyResolver() const; + const xmltooling::XMLObject* getMetadata() const; + const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const; + const EntityDescriptor* getEntityDescriptor(const char* id, bool requireValidMetadata=true) const; + const EntityDescriptor* getEntityDescriptor(const SAMLArtifact* artifact) const; + void onEvent(MetadataProvider& provider); + + private: + xmltooling::ThreadKey* m_tlsKey; + std::vector m_providers; + }; + }; +}; + +#endif /* __saml_chainmeta_h__ */ diff --git a/saml/saml2/metadata/MetadataProvider.h b/saml/saml2/metadata/MetadataProvider.h index bc3f164..3a297d5 100644 --- a/saml/saml2/metadata/MetadataProvider.h +++ b/saml/saml2/metadata/MetadataProvider.h @@ -54,12 +54,10 @@ namespace opensaml { * * If a DOM is supplied, a set of default logic will be used to identify * and build MetadataFilter plugins and install them into the provider. - * A KeyResolver can also be supplied, or a default resolver will be used. * * The following XML content is supported: * *
    - *
  • <KeyResolver> elements with a type attribute *
  • <MetadataFilter> elements with a type attribute and type-specific content *
  • <Exclude> elements representing a BlacklistMetadataFilter *
  • <BlacklistMetadataFilter> element containing <Exclude> elements @@ -120,9 +118,7 @@ namespace opensaml { * * @return an associated KeyResolver, or NULL */ - virtual const xmlsignature::KeyResolver* getKeyResolver() const { - return m_resolver; - } + virtual const xmlsignature::KeyResolver* getKeyResolver() const=0; /** * Gets the entire metadata tree, after the registered filter has been applied. @@ -154,7 +150,7 @@ namespace opensaml { * * @return the entity's metadata or NULL if there is no metadata or no valid metadata */ - virtual const EntityDescriptor* getEntityDescriptor(const char* id, bool requireValidMetadata=true) const; + virtual const EntityDescriptor* getEntityDescriptor(const char* id, bool requireValidMetadata=true) const=0; /** * Gets the metadata for an entity that issued a SAML artifact. If a valid entity is returned, @@ -165,7 +161,7 @@ namespace opensaml { * * @return the entity's metadata or NULL if there is no valid metadata */ - virtual const EntityDescriptor* getEntityDescriptor(const SAMLArtifact* artifact) const; + virtual const EntityDescriptor* getEntityDescriptor(const SAMLArtifact* artifact) const=0; /** * Gets the metadata for a given group of entities. If a valid group is returned, @@ -189,12 +185,9 @@ namespace opensaml { * * @return the group's metadata or NULL if there is no metadata or no valid metadata */ - virtual const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const; + virtual const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const=0; protected: - /** Embedded KeyResolver instance. */ - xmlsignature::KeyResolver* m_resolver; - /** * Applies any installed filters to a metadata instance. * @@ -202,36 +195,8 @@ namespace opensaml { */ void doFilters(xmltooling::XMLObject& xmlObject) const; - /** - * Loads an entity into the cache for faster lookup. This includes - * processing known reverse lookup strategies for artifacts. - * - * @param site entity definition - * @param validUntil expiration time of the entity definition - */ - virtual void index(EntityDescriptor* site, time_t validUntil); - - /** - * Loads a group of entities into the cache for faster lookup. - * - * @param group group definition - * @param validUntil expiration time of the group definition - */ - virtual void index(EntitiesDescriptor* group, time_t validUntil); - - /** - * Clear the cache of known entities and groups. - */ - virtual void clearDescriptorIndex(); - private: std::vector m_filters; - - typedef std::multimap sitemap_t; - typedef std::multimap groupmap_t; - sitemap_t m_sites; - sitemap_t m_sources; - groupmap_t m_groups; }; /** @@ -241,6 +206,9 @@ namespace opensaml { /** MetadataProvider based on local XML files */ #define FILESYSTEM_METADATA_PROVIDER "org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider" + + /** MetadataProvider that wraps a sequence of metadata providers. */ + #define CHAINING_METADATA_PROVIDER "org.opensaml.saml2.metadata.provider.ChainingMetadataProvider" }; }; diff --git a/saml/saml2/metadata/ObservableMetadataProvider.h b/saml/saml2/metadata/ObservableMetadataProvider.h index e1b1ae5..3de1eb3 100644 --- a/saml/saml2/metadata/ObservableMetadataProvider.h +++ b/saml/saml2/metadata/ObservableMetadataProvider.h @@ -40,12 +40,12 @@ namespace opensaml { * * @param e DOM to supply configuration for provider */ - ObservableMetadataProvider(const DOMElement* e) : MetadataProvider(e) {} + ObservableMetadataProvider(const DOMElement* e=NULL) : MetadataProvider(e) {} /** * Convenience method for notifying every registered Observer of an event. */ - void emitChangeEvent(); + virtual void emitChangeEvent(); public: /** diff --git a/saml/saml2/metadata/impl/AbstractMetadataProvider.cpp b/saml/saml2/metadata/impl/AbstractMetadataProvider.cpp new file mode 100644 index 0000000..59e4303 --- /dev/null +++ b/saml/saml2/metadata/impl/AbstractMetadataProvider.cpp @@ -0,0 +1,190 @@ +/* + * 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. + */ + +/** + * AbstractMetadataProvider.cpp + * + * Base class for caching metadata providers. + */ + +#include "internal.h" +#include "SAMLArtifact.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/AbstractMetadataProvider.h" + +#include +#include +#include + +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xmltooling; +using namespace std; + +static const XMLCh GenericKeyResolver[] = UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r); +static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); + +AbstractMetadataProvider::AbstractMetadataProvider(const DOMElement* e) : ObservableMetadataProvider(e), m_resolver(NULL) +{ + e = e ? XMLHelper::getFirstChildElement(e, GenericKeyResolver) : NULL; + if (e) { + auto_ptr_char t(e->getAttributeNS(NULL,type)); + if (t.get()) + m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),e); + else + throw UnknownExtensionException(" element found with no type attribute"); + } + + if (!m_resolver) { + m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER, NULL); + } +} + +AbstractMetadataProvider::~AbstractMetadataProvider() +{ + delete m_resolver; +} + +void AbstractMetadataProvider::emitChangeEvent() +{ + xmlsignature::CachingKeyResolver* ckr=dynamic_cast(m_resolver); + if (ckr) + ckr->clearCache(); + ObservableMetadataProvider::emitChangeEvent(); +} + +void AbstractMetadataProvider::index(EntityDescriptor* site, time_t validUntil) +{ + if (validUntil < site->getValidUntilEpoch()) + site->setValidUntil(validUntil); + + auto_ptr_char id(site->getEntityID()); + if (id.get()) { + m_sites.insert(make_pair(id.get(),site)); + } + + // Process each IdP role. + const vector& roles=const_cast(site)->getIDPSSODescriptors(); + for (vector::const_iterator i=roles.begin(); i!=roles.end(); i++) { + // SAML 1.x? + if ((*i)->hasSupport(SAMLConstants::SAML10_PROTOCOL_ENUM) || (*i)->hasSupport(SAMLConstants::SAML11_PROTOCOL_ENUM)) { + // Check for SourceID extension element. + const Extensions* exts=(*i)->getExtensions(); + if (exts) { + const list& children=exts->getXMLObjects(); + for (list::const_iterator ext=children.begin(); ext!=children.end(); ext++) { + SourceID* sid=dynamic_cast(*ext); + if (sid) { + auto_ptr_char sourceid(sid->getID()); + if (sourceid.get()) { + m_sources.insert(pair(sourceid.get(),site)); + break; + } + } + } + } + + // Hash the ID. + m_sources.insert( + pair(SAMLConfig::getConfig().hashSHA1(id.get(), true),site) + ); + + // Load endpoints for type 0x0002 artifacts. + const vector& locs=const_cast(*i)->getArtifactResolutionServices(); + for (vector::const_iterator loc=locs.begin(); loc!=locs.end(); loc++) { + auto_ptr_char location((*loc)->getLocation()); + if (location.get()) + m_sources.insert(pair(location.get(),site)); + } + } + + // SAML 2.0? + if ((*i)->hasSupport(SAMLConstants::SAML20P_NS)) { + // Hash the ID. + m_sources.insert( + pair(SAMLConfig::getConfig().hashSHA1(id.get(), true),site) + ); + } + } +} + +void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUntil) +{ + if (validUntil < group->getValidUntilEpoch()) + group->setValidUntil(validUntil); + + auto_ptr_char name(group->getName()); + if (name.get()) { + m_groups.insert(make_pair(name.get(),group)); + } + + const vector& groups=const_cast(group)->getEntitiesDescriptors(); + for (vector::const_iterator i=groups.begin(); i!=groups.end(); i++) + index(*i,group->getValidUntilEpoch()); + + const vector& sites=const_cast(group)->getEntityDescriptors(); + for (vector::const_iterator j=sites.begin(); j!=sites.end(); j++) + index(*j,group->getValidUntilEpoch()); +} + +void AbstractMetadataProvider::clearDescriptorIndex() +{ + m_sources.clear(); + m_sites.clear(); + m_groups.clear(); +} + +const EntitiesDescriptor* AbstractMetadataProvider::getEntitiesDescriptor(const char* name, bool strict) const +{ + pair range=m_groups.equal_range(name); + + time_t now=time(NULL); + for (groupmap_t::const_iterator i=range.first; i!=range.second; i++) + if (now < i->second->getValidUntilEpoch()) + return i->second; + + if (!strict && range.first!=range.second) + return range.first->second; + + return NULL; +} + +const EntityDescriptor* AbstractMetadataProvider::getEntityDescriptor(const char* name, bool strict) const +{ + pair range=m_sites.equal_range(name); + + time_t now=time(NULL); + for (sitemap_t::const_iterator i=range.first; i!=range.second; i++) + if (now < i->second->getValidUntilEpoch()) + return i->second; + + if (!strict && range.first!=range.second) + return range.first->second; + + return NULL; +} + +const EntityDescriptor* AbstractMetadataProvider::getEntityDescriptor(const SAMLArtifact* artifact) const +{ + pair range=m_sources.equal_range(artifact->getSource()); + + time_t now=time(NULL); + for (sitemap_t::const_iterator i=range.first; i!=range.second; i++) + if (now < i->second->getValidUntilEpoch()) + return i->second; + + return NULL; +} diff --git a/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp new file mode 100644 index 0000000..7f410d2 --- /dev/null +++ b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp @@ -0,0 +1,176 @@ +/* + * Copyright 2001-2005 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. + */ + +/** + * ChainingMetadataProvider.cpp + * + * MetadataProvider that uses multiple providers in sequence. + */ + +#include "internal.h" +#include "exceptions.h" +#include "saml2/metadata/ChainingMetadataProvider.h" + +#include +#include + +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xmlsignature; +using namespace xmltooling; +using namespace std; + +namespace opensaml { + namespace saml2md { + MetadataProvider* SAML_DLLLOCAL ChainingMetadataProviderFactory(const DOMElement* const & e) + { + return new ChainingMetadataProvider(e); + } + }; +}; + +static const XMLCh GenericMetadataProvider[] = UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r); +static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); + +ChainingMetadataProvider::ChainingMetadataProvider(const DOMElement* e) : ObservableMetadataProvider(e), m_tlsKey(NULL) +{ + try { + e = e ? xmltooling::XMLHelper::getFirstChildElement(e, GenericMetadataProvider) : NULL; + while (e) { + auto_ptr_char temp(e->getAttributeNS(NULL,type)); + if (temp.get()) { + auto_ptr provider( + SAMLConfig::getConfig().MetadataProviderManager.newPlugin(temp.get(), e) + ); + ObservableMetadataProvider* obs = dynamic_cast(provider.get()); + if (obs) + obs->addObserver(this); + m_providers.push_back(provider.get()); + provider.release(); + } + e = XMLHelper::getNextSiblingElement(e, GenericMetadataProvider); + } + } + catch (XMLToolingException&) { + for_each(m_providers.begin(), m_providers.end(), xmltooling::cleanup()); + throw; + } + m_tlsKey = ThreadKey::create(NULL); +} + +ChainingMetadataProvider::~ChainingMetadataProvider() +{ + delete m_tlsKey; + for_each(m_providers.begin(), m_providers.end(), xmltooling::cleanup()); +} + +void ChainingMetadataProvider::onEvent(MetadataProvider& provider) +{ + emitChangeEvent(); +} + +void ChainingMetadataProvider::init() +{ + for_each(m_providers.begin(), m_providers.end(), mem_fun(&MetadataProvider::init)); +} + +Lockable* ChainingMetadataProvider::lock() +{ + return this; // we're not lockable ourselves... +} + +void ChainingMetadataProvider::unlock() +{ + // Check for a locked provider. + void* ptr=m_tlsKey->getData(); + if (ptr) { + m_tlsKey->setData(NULL); + reinterpret_cast(ptr)->unlock(); + } +} + +const KeyResolver* ChainingMetadataProvider::getKeyResolver() const +{ + // Check for a locked provider. + void* ptr=m_tlsKey->getData(); + return ptr ? reinterpret_cast(ptr)->getKeyResolver() : NULL; + +} + +const XMLObject* ChainingMetadataProvider::getMetadata() const +{ + throw XMLToolingException("getMetadata operation not implemented on this provider."); +} + +const EntitiesDescriptor* ChainingMetadataProvider::getEntitiesDescriptor(const char* name, bool requireValidMetadata) const +{ + // Clear any existing lock. + const_cast(this)->unlock(); + + // Do a search. + const EntitiesDescriptor* ret=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; + } + (*i)->unlock(); + } + + return NULL; +} + +const EntityDescriptor* ChainingMetadataProvider::getEntityDescriptor(const char* id, bool requireValidMetadata) const +{ + // Clear any existing lock. + const_cast(this)->unlock(); + + // Do a search. + const EntityDescriptor* ret=NULL; + for (vector::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) { + (*i)->lock(); + if (ret=(*i)->getEntityDescriptor(id,requireValidMetadata)) { + // Save locked provider. + m_tlsKey->setData(*i); + return ret; + } + (*i)->unlock(); + } + + return NULL; +} + +const EntityDescriptor* ChainingMetadataProvider::getEntityDescriptor(const SAMLArtifact* artifact) const +{ + // Clear any existing lock. + const_cast(this)->unlock(); + + // Do a search. + const EntityDescriptor* ret=NULL; + for (vector::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) { + (*i)->lock(); + if (ret=(*i)->getEntityDescriptor(artifact)) { + // Save locked provider. + m_tlsKey->setData(*i); + return ret; + } + (*i)->unlock(); + } + + return NULL; +} diff --git a/saml/saml2/metadata/impl/FilesystemMetadataProvider.cpp b/saml/saml2/metadata/impl/FilesystemMetadataProvider.cpp index c5b210e..8651747 100644 --- a/saml/saml2/metadata/impl/FilesystemMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/FilesystemMetadataProvider.cpp @@ -22,7 +22,7 @@ #include "internal.h" #include "saml2/metadata/Metadata.h" -#include "saml2/metadata/ObservableMetadataProvider.h" +#include "saml2/metadata/AbstractMetadataProvider.h" #include #include @@ -44,7 +44,7 @@ namespace opensaml { namespace saml2md { - class SAML_DLLLOCAL FilesystemMetadataProvider : public ObservableMetadataProvider + class SAML_DLLLOCAL FilesystemMetadataProvider : public AbstractMetadataProvider { public: FilesystemMetadataProvider(const DOMElement* e); @@ -91,7 +91,7 @@ static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e); static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e); FilesystemMetadataProvider::FilesystemMetadataProvider(const DOMElement* e) - : ObservableMetadataProvider(e), m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL) + : AbstractMetadataProvider(e), m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL) { #ifdef _DEBUG NDC ndc("FilesystemMetadataProvider"); @@ -257,9 +257,9 @@ void FilesystemMetadataProvider::index() clearDescriptorIndex(); EntitiesDescriptor* group=dynamic_cast(m_object); if (group) { - MetadataProvider::index(group, SAMLTIME_MAX); + AbstractMetadataProvider::index(group, SAMLTIME_MAX); return; } EntityDescriptor* site=dynamic_cast(m_object); - MetadataProvider::index(site, SAMLTIME_MAX); + AbstractMetadataProvider::index(site, SAMLTIME_MAX); } diff --git a/saml/saml2/metadata/impl/MetadataProvider.cpp b/saml/saml2/metadata/impl/MetadataProvider.cpp index fc5d7de..8c01e62 100644 --- a/saml/saml2/metadata/impl/MetadataProvider.cpp +++ b/saml/saml2/metadata/impl/MetadataProvider.cpp @@ -21,8 +21,6 @@ */ #include "internal.h" -#include "SAMLArtifact.h" -#include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataProvider.h" #include @@ -38,10 +36,11 @@ using namespace std; namespace opensaml { namespace saml2md { - SAML_DLLLOCAL PluginManager::Factory FilesystemMetadataProviderFactory; - SAML_DLLLOCAL PluginManager::Factory BlacklistMetadataFilterFactory; - SAML_DLLLOCAL PluginManager::Factory WhitelistMetadataFilterFactory; - SAML_DLLLOCAL PluginManager::Factory SignatureMetadataFilterFactory; + SAML_DLLLOCAL PluginManager::Factory FilesystemMetadataProviderFactory; + SAML_DLLLOCAL PluginManager::Factory ChainingMetadataProviderFactory; + SAML_DLLLOCAL PluginManager::Factory BlacklistMetadataFilterFactory; + SAML_DLLLOCAL PluginManager::Factory WhitelistMetadataFilterFactory; + SAML_DLLLOCAL PluginManager::Factory SignatureMetadataFilterFactory; }; }; @@ -49,6 +48,7 @@ void SAML_API opensaml::saml2md::registerMetadataProviders() { SAMLConfig& conf=SAMLConfig::getConfig(); conf.MetadataProviderManager.registerFactory(FILESYSTEM_METADATA_PROVIDER, FilesystemMetadataProviderFactory); + conf.MetadataProviderManager.registerFactory(CHAINING_METADATA_PROVIDER, ChainingMetadataProviderFactory); conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata", FilesystemMetadataProviderFactory); conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.common.provider.XMLMetadata", FilesystemMetadataProviderFactory); } @@ -65,11 +65,10 @@ static const XMLCh Whitelist[] = UNICODE_LITERAL_23(W,h,i,t,e static const XMLCh SigFilter[] = UNICODE_LITERAL_23(S,i,g,n,a,t,u,r,e,M,e,t,a,d,a,t,a,F,i,l,t,e,r); static const XMLCh Exclude[] = UNICODE_LITERAL_7(E,x,c,l,u,d,e); static const XMLCh Include[] = UNICODE_LITERAL_7(I,n,c,l,u,d,e); -static const XMLCh GenericKeyResolver[] = UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r); static const XMLCh GenericMetadataFilter[] = UNICODE_LITERAL_14(M,e,t,a,d,a,t,a,F,i,l,t,e,r); static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); -MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL) +MetadataProvider::MetadataProvider(const DOMElement* e) { #ifdef _DEBUG NDC ndc("MetadataProvider"); @@ -80,14 +79,7 @@ MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL) try { DOMElement* child = e ? XMLHelper::getFirstChildElement(e) : NULL; while (child) { - if (!m_resolver && XMLString::equals(child->getLocalName(),GenericKeyResolver)) { - auto_ptr_char t(child->getAttributeNS(NULL,type)); - if (t.get()) - m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child); - else - throw UnknownExtensionException(" element found with no type attribute"); - } - else if (XMLString::equals(child->getLocalName(),GenericMetadataFilter)) { + if (XMLString::equals(child->getLocalName(),GenericMetadataFilter)) { auto_ptr_char t(child->getAttributeNS(NULL,type)); if (t.get()) m_filters.push_back(conf.MetadataFilterManager.newPlugin(t.get(),child)); @@ -111,14 +103,9 @@ MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL) } child = XMLHelper::getNextSiblingElement(child); } - - if (!m_resolver) { - m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(INLINE_KEY_RESOLVER, child); - } } catch (XMLToolingException& ex) { - Category::getInstance(SAML_LOGCAT".Metadata").error("caught exception while installing plugins and filters: %s", ex.what()); - delete m_resolver; + Category::getInstance(SAML_LOGCAT".Metadata").error("caught exception while installing filters: %s", ex.what()); for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup()); throw; } @@ -126,7 +113,6 @@ MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL) MetadataProvider::~MetadataProvider() { - delete m_resolver; for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup()); } @@ -142,137 +128,14 @@ void MetadataProvider::doFilters(XMLObject& xmlObject) const } } -void MetadataProvider::index(EntityDescriptor* site, time_t validUntil) -{ - if (validUntil < site->getValidUntilEpoch()) - site->setValidUntil(validUntil); - - auto_ptr_char id(site->getEntityID()); - if (id.get()) { - m_sites.insert(make_pair(id.get(),site)); - } - - // Process each IdP role. - const vector& roles=const_cast(site)->getIDPSSODescriptors(); - for (vector::const_iterator i=roles.begin(); i!=roles.end(); i++) { - // SAML 1.x? - if ((*i)->hasSupport(SAMLConstants::SAML10_PROTOCOL_ENUM) || (*i)->hasSupport(SAMLConstants::SAML11_PROTOCOL_ENUM)) { - // Check for SourceID extension element. - const Extensions* exts=(*i)->getExtensions(); - if (exts) { - const list& children=exts->getXMLObjects(); - for (list::const_iterator ext=children.begin(); ext!=children.end(); ext++) { - SourceID* sid=dynamic_cast(*ext); - if (sid) { - auto_ptr_char sourceid(sid->getID()); - if (sourceid.get()) { - m_sources.insert(pair(sourceid.get(),site)); - break; - } - } - } - } - - // Hash the ID. - m_sources.insert( - pair(SAMLConfig::getConfig().hashSHA1(id.get(), true),site) - ); - - // Load endpoints for type 0x0002 artifacts. - const vector& locs=const_cast(*i)->getArtifactResolutionServices(); - for (vector::const_iterator loc=locs.begin(); loc!=locs.end(); loc++) { - auto_ptr_char location((*loc)->getLocation()); - if (location.get()) - m_sources.insert(pair(location.get(),site)); - } - } - - // SAML 2.0? - if ((*i)->hasSupport(SAMLConstants::SAML20P_NS)) { - // Hash the ID. - m_sources.insert( - pair(SAMLConfig::getConfig().hashSHA1(id.get(), true),site) - ); - } - } -} - -void MetadataProvider::index(EntitiesDescriptor* group, time_t validUntil) -{ - if (validUntil < group->getValidUntilEpoch()) - group->setValidUntil(validUntil); - - auto_ptr_char name(group->getName()); - if (name.get()) { - m_groups.insert(make_pair(name.get(),group)); - } - - const vector& groups=const_cast(group)->getEntitiesDescriptors(); - for (vector::const_iterator i=groups.begin(); i!=groups.end(); i++) - index(*i,group->getValidUntilEpoch()); - - const vector& sites=const_cast(group)->getEntityDescriptors(); - for (vector::const_iterator j=sites.begin(); j!=sites.end(); j++) - index(*j,group->getValidUntilEpoch()); -} - -void MetadataProvider::clearDescriptorIndex() -{ - m_sources.clear(); - m_sites.clear(); - m_groups.clear(); -} - -const EntitiesDescriptor* MetadataProvider::getEntitiesDescriptor(const char* name, bool strict) const -{ - pair range=m_groups.equal_range(name); - - time_t now=time(NULL); - for (groupmap_t::const_iterator i=range.first; i!=range.second; i++) - if (now < i->second->getValidUntilEpoch()) - return i->second; - - if (!strict && range.first!=range.second) - return range.first->second; - - return NULL; -} - const EntitiesDescriptor* MetadataProvider::getEntitiesDescriptor(const XMLCh* name, bool strict) const { auto_ptr_char temp(name); return getEntitiesDescriptor(temp.get(),strict); } -const EntityDescriptor* MetadataProvider::getEntityDescriptor(const char* name, bool strict) const -{ - pair range=m_sites.equal_range(name); - - time_t now=time(NULL); - for (sitemap_t::const_iterator i=range.first; i!=range.second; i++) - if (now < i->second->getValidUntilEpoch()) - return i->second; - - if (!strict && range.first!=range.second) - return range.first->second; - - return NULL; -} - const EntityDescriptor* MetadataProvider::getEntityDescriptor(const XMLCh* name, bool strict) const { auto_ptr_char temp(name); return getEntityDescriptor(temp.get(),strict); } - -const EntityDescriptor* MetadataProvider::getEntityDescriptor(const SAMLArtifact* artifact) const -{ - pair range=m_sources.equal_range(artifact->getSource()); - - time_t now=time(NULL); - for (sitemap_t::const_iterator i=range.first; i!=range.second; i++) - if (now < i->second->getValidUntilEpoch()) - return i->second; - - return NULL; -} diff --git a/saml/saml2/metadata/impl/ObservableMetadataProvider.cpp b/saml/saml2/metadata/impl/ObservableMetadataProvider.cpp index 069a1e2..569c030 100644 --- a/saml/saml2/metadata/impl/ObservableMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/ObservableMetadataProvider.cpp @@ -23,8 +23,6 @@ #include "internal.h" #include "saml2/metadata/ObservableMetadataProvider.h" -#include - using namespace opensaml::saml2md; using namespace std; @@ -35,10 +33,6 @@ ObservableMetadataProvider::~ObservableMetadataProvider() void ObservableMetadataProvider::emitChangeEvent() { - xmlsignature::CachingKeyResolver* ckr=dynamic_cast(m_resolver); - if (ckr) - ckr->clearCache(); - for (std::vector::const_iterator i=m_observers.begin(); i!=m_observers.end(); i++) { (*i)->onEvent(*this); } diff --git a/saml/security/ChainingTrustEngine.h b/saml/security/ChainingTrustEngine.h new file mode 100644 index 0000000..9e80dc5 --- /dev/null +++ b/saml/security/ChainingTrustEngine.h @@ -0,0 +1,99 @@ +/* + * 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/security/ChainingTrustEngine.h + * + * X509TrustEngine that uses multiple engines in sequence. + */ + +#ifndef __saml_chaintrust_h__ +#define __saml_chaintrust_h__ + +#include + +namespace opensaml { + + /** + * X509TrustEngine that uses multiple engines in sequence. + */ + class SAML_API ChainingTrustEngine : public X509TrustEngine { + public: + /** + * Constructor. + * + * If a DOM is supplied, the following XML content is supported: + * + *
      + *
    • <TrustEngine> elements with a type attribute + *
    + * + * XML namespaces are ignored in the processing of this content. + * + * @param e DOM to supply configuration for provider + */ + ChainingTrustEngine(const DOMElement* e=NULL); + + /** + * Destructor will delete any embedded engines. + */ + virtual ~ChainingTrustEngine(); + + /** + * Adds a trust engine for future calls. + * + * @param newEngine trust engine to add + */ + void addTrustEngine(X509TrustEngine* newEngine) { + m_engines.push_back(newEngine); + } + + /** + * Removes a trust engine. The caller must delete the engine if necessary. + * + * @param oldEngine trust engine to remove + * @return the old engine + */ + X509TrustEngine* removeTrustEngine(X509TrustEngine* oldEngine) { + for (std::vector::iterator i=m_engines.begin(); i!=m_engines.end(); i++) { + if (oldEngine==(*i)) { + m_engines.erase(i); + return oldEngine; + } + } + return NULL; + } + + virtual bool validate( + xmlsignature::Signature& sig, + const saml2md::RoleDescriptor& role, + const xmlsignature::KeyResolver* keyResolver=NULL + ); + virtual bool validate( + XSECCryptoX509* certEE, + const std::vector& certChain, + const saml2md::RoleDescriptor& role, + bool checkName=true, + const xmlsignature::KeyResolver* keyResolver=NULL + ); + + private: + std::vector m_engines; + }; + +}; + +#endif /* __saml_chaintrust_h__ */ diff --git a/saml/security/TrustEngine.h b/saml/security/TrustEngine.h index 0cc211f..e07774d 100644 --- a/saml/security/TrustEngine.h +++ b/saml/security/TrustEngine.h @@ -81,6 +81,9 @@ namespace opensaml { /** TrustEngine based on explicit key information resolved from metadata. */ #define EXPLICIT_KEY_SAMLTRUSTENGINE "org.opensaml.security.ExplicitKeyTrustEngine" + + /** TrustEngine that tries multiple engines in sequence. */ + #define CHAINING_SAMLTRUSTENGINE "org.opensaml.security.ChainingTrustEngine" }; #endif /* __saml_trust_h__ */ diff --git a/saml/security/impl/ChainingTrustEngine.cpp b/saml/security/impl/ChainingTrustEngine.cpp new file mode 100644 index 0000000..ef8634b --- /dev/null +++ b/saml/security/impl/ChainingTrustEngine.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2001-2005 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. + */ + +/** + * ChainingTrustEngine.cpp + * + * TrustEngine that uses multiple engines in sequence. + */ + +#include "internal.h" +#include "exceptions.h" +#include "security/ChainingTrustEngine.h" + +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xmlsignature; +using namespace std; + +namespace opensaml { + TrustEngine* SAML_DLLLOCAL ChainingTrustEngineFactory(const DOMElement* const & e) + { + return new ChainingTrustEngine(e); + } +}; + +static const XMLCh GenericTrustEngine[] = UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e); +static const XMLCh type[] = UNICODE_LITERAL_4(t,y,p,e); + +ChainingTrustEngine::ChainingTrustEngine(const DOMElement* e) { + try { + e = e ? xmltooling::XMLHelper::getFirstChildElement(e, GenericTrustEngine) : NULL; + while (e) { + xmltooling::auto_ptr_char temp(e->getAttributeNS(NULL,type)); + if (temp.get()) { + auto_ptr engine( + SAMLConfig::getConfig().TrustEngineManager.newPlugin(temp.get(), e) + ); + X509TrustEngine* x509 = dynamic_cast(engine.get()); + if (x509) { + m_engines.push_back(x509); + engine.release(); + } + else { + throw xmltooling::UnknownExtensionException("Embedded trust engine does not support required interface."); + } + } + e = xmltooling::XMLHelper::getNextSiblingElement(e, GenericTrustEngine); + } + } + catch (xmltooling::XMLToolingException&) { + for_each(m_engines.begin(), m_engines.end(), xmltooling::cleanup()); + throw; + } +} + +ChainingTrustEngine::~ChainingTrustEngine() { + for_each(m_engines.begin(), m_engines.end(), xmltooling::cleanup()); +} + +bool ChainingTrustEngine::validate( + Signature& sig, + const RoleDescriptor& role, + const KeyResolver* keyResolver + ) +{ + for (vector::iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { + if (static_cast(*i)->validate(sig,role,keyResolver)) + return true; + } + return false; +} + +bool ChainingTrustEngine::validate( + XSECCryptoX509* certEE, + const vector& certChain, + const RoleDescriptor& role, + bool checkName, + const KeyResolver* keyResolver + ) +{ + for (vector::iterator i=m_engines.begin(); i!=m_engines.end(); ++i) { + if ((*i)->validate(certEE,certChain,role,checkName,keyResolver)) + return true; + } + return false; +} diff --git a/saml/security/impl/TrustEngine.cpp b/saml/security/impl/TrustEngine.cpp index f5084c2..e33f4b0 100644 --- a/saml/security/impl/TrustEngine.cpp +++ b/saml/security/impl/TrustEngine.cpp @@ -29,10 +29,12 @@ using namespace std; namespace opensaml { SAML_DLLLOCAL PluginManager::Factory ExplicitKeyTrustEngineFactory; + SAML_DLLLOCAL PluginManager::Factory ChainingTrustEngineFactory; }; void SAML_API opensaml::registerTrustEngines() { SAMLConfig& conf=SAMLConfig::getConfig(); conf.TrustEngineManager.registerFactory(EXPLICIT_KEY_SAMLTRUSTENGINE, ExplicitKeyTrustEngineFactory); + conf.TrustEngineManager.registerFactory(CHAINING_SAMLTRUSTENGINE, ChainingTrustEngineFactory); } -- 2.1.4