saml2mdinclude_HEADERS = \
saml2/metadata/AbstractMetadataProvider.h \
saml2/metadata/ChainingMetadataProvider.h \
+ saml2/metadata/DynamicMetadataProvider.h \
saml2/metadata/EndpointManager.h \
saml2/metadata/Metadata.h \
saml2/metadata/MetadataCredentialContext.h \
saml2/metadata/impl/AbstractMetadataProvider.cpp \
saml2/metadata/impl/BlacklistMetadataFilter.cpp \
saml2/metadata/impl/ChainingMetadataProvider.cpp \
+ saml2/metadata/impl/DynamicMetadataProvider.cpp \
saml2/metadata/impl/MetadataImpl.cpp \
saml2/metadata/impl/MetadataProvider.cpp \
saml2/metadata/impl/MetadataSchemaValidators.cpp \
>\r
</File>\r
<File\r
+ RelativePath=".\saml2\metadata\impl\DynamicMetadataProvider.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\saml2\metadata\impl\MetadataImpl.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\saml2\metadata\DynamicMetadataProvider.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\saml2\metadata\EndpointManager.h"\r
>\r
</File>\r
* processing known reverse lookup strategies for artifacts.
*
* @param site entity definition
- * @param validUntil expiration time of the entity definition
+ * @param validUntil maximum expiration time of the entity definition
+ * @param replace true iff existing entries for the same entity should be cleared/replaced
*/
- virtual void index(EntityDescriptor* site, time_t validUntil);
+ virtual void index(EntityDescriptor* site, time_t validUntil, bool replace=false) const;
/**
* Loads a group of entities into the cache for faster lookup.
*
* @param group group definition
- * @param validUntil expiration time of the group definition
+ * @param validUntil maximum expiration time of the group definition
*/
- virtual void index(EntitiesDescriptor* group, time_t validUntil);
+ virtual void index(EntitiesDescriptor* group, time_t validUntil) const;
/**
* Clear the cache of known entities and groups.
+ *
+ * @param freeSites true iff the objects cached in the site map should be freed.
*/
- virtual void clearDescriptorIndex();
+ virtual void clearDescriptorIndex(bool freeSites=false);
private:
typedef std::multimap<std::string,const EntityDescriptor*> sitemap_t;
typedef std::multimap<std::string,const EntitiesDescriptor*> groupmap_t;
- sitemap_t m_sites;
- sitemap_t m_sources;
- groupmap_t m_groups;
+ mutable sitemap_t m_sites;
+ mutable sitemap_t m_sources;
+ mutable groupmap_t m_groups;
mutable xmltooling::Mutex* m_credentialLock;
typedef std::map< const RoleDescriptor*, std::vector<xmltooling::Credential*> > credmap_t;
--- /dev/null
+/*
+ * Copyright 2001-2007 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/DynamicMetadataProvider.h
+ *
+ * Simple implementation of a dynamic caching MetadataProvider.
+ */
+
+#ifndef __saml2_dynmetadataprov_h__
+#define __saml2_dynmetadataprov_h__
+
+#include <saml/saml2/metadata/AbstractMetadataProvider.h>
+
+namespace opensaml {
+ namespace saml2md {
+
+ /**
+ * Simple implementation of a dynamic, caching MetadataProvider.
+ */
+ class SAML_API DynamicMetadataProvider : public AbstractMetadataProvider
+ {
+ public:
+ /**
+ * Constructor.
+ *
+ * @param e DOM to supply configuration for provider
+ */
+ DynamicMetadataProvider(const xercesc::DOMElement* e=NULL);
+
+ virtual ~DynamicMetadataProvider();
+
+ xmltooling::Lockable* lock() {
+ m_lock->rdlock();
+ return this;
+ }
+
+ void unlock() {
+ m_lock->unlock();
+ }
+
+ void init() {
+ }
+
+ const xmltooling::XMLObject* getMetadata() const {
+ throw MetadataException("getMetadata operation not implemented on this provider.");
+ }
+
+ const EntityDescriptor* getEntityDescriptor(const char* id, bool requireValidMetadata=true) const;
+
+ protected:
+ /** Controls XML schema validation. */
+ bool m_validate;
+
+ /**
+ * Resolves an entityID into a metadata instance for that entity.
+ *
+ * @param entityID entity ID to resolve
+ * @return a valid metadata instance
+ */
+ virtual EntityDescriptor* resolve(const char* entityID) const;
+
+ private:
+ mutable xmltooling::RWLock* m_lock;
+ };
+
+ };
+};
+
+#endif /* __saml2_dynmetadataprov_h__ */
/** MetadataProvider based on local or remote XML file */
#define XML_METADATA_PROVIDER "XML"
+ /** MetadataProvider based on dynamic resolution */
+ #define DYNAMIC_METADATA_PROVIDER "Dynamic"
+
/** MetadataProvider that wraps a sequence of metadata providers. */
#define CHAINING_METADATA_PROVIDER "Chaining"
ObservableMetadataProvider::emitChangeEvent();
}
-void AbstractMetadataProvider::index(EntityDescriptor* site, time_t validUntil)
+void AbstractMetadataProvider::index(EntityDescriptor* site, time_t validUntil, bool replace) const
{
if (validUntil < site->getValidUntilEpoch())
site->setValidUntil(validUntil);
auto_ptr_char id(site->getEntityID());
if (id.get()) {
+ if (replace) {
+ m_sites.erase(id.get());
+ for (sitemap_t::iterator s = m_sources.begin(); s != m_sources.end();) {
+ if (s->second == site) {
+ sitemap_t::iterator temp = s;
+ ++s;
+ m_sources.erase(temp);
+ }
+ else {
+ ++s;
+ }
+ }
+ }
m_sites.insert(sitemap_t::value_type(id.get(),site));
}
}
}
-void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUntil)
+void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUntil) const
{
if (validUntil < group->getValidUntilEpoch())
group->setValidUntil(validUntil);
index(*j,group->getValidUntilEpoch());
}
-void AbstractMetadataProvider::clearDescriptorIndex()
+void AbstractMetadataProvider::clearDescriptorIndex(bool freeSites)
{
- m_sources.clear();
+ if (freeSites)
+ for_each(m_sites.begin(), m_sites.end(), cleanup_const_pair<string,EntityDescriptor>());
m_sites.clear();
m_groups.clear();
+ m_sources.clear();
}
const EntitiesDescriptor* AbstractMetadataProvider::getEntitiesDescriptor(const char* name, bool strict) const
const XMLObject* ChainingMetadataProvider::getMetadata() const
{
- throw XMLToolingException("getMetadata operation not implemented on this provider.");
+ throw MetadataException("getMetadata operation not implemented on this provider.");
}
const EntitiesDescriptor* ChainingMetadataProvider::getEntitiesDescriptor(const char* name, bool requireValidMetadata) const
--- /dev/null
+/*
+ * Copyright 2001-2007 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.
+ */
+
+/**
+ * DynamicMetadataProvider.cpp
+ *
+ * Base class for caching metadata providers.
+ */
+
+#include "internal.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/DynamicMetadataProvider.h"
+
+#include <xercesc/framework/Wrapper4InputSource.hpp>\r
+#include <xercesc/framework/URLInputSource.hpp>\r
+#include <xercesc/util/XMLUniDefs.hpp>\r
+#include <xmltooling/logging.h>\r
+#include <xmltooling/util/XMLHelper.h>
+
+using namespace opensaml::saml2md;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
+
+namespace opensaml {
+ namespace saml2md {
+ MetadataProvider* SAML_DLLLOCAL DynamicMetadataProviderFactory(const DOMElement* const & e)
+ {
+ return new DynamicMetadataProvider(e);
+ }
+ };
+};
+
+DynamicMetadataProvider::DynamicMetadataProvider(const DOMElement* e)
+ : AbstractMetadataProvider(e), m_lock(RWLock::create())
+{
+ const XMLCh* flag=e ? e->getAttributeNS(NULL,validate) : NULL;\r
+ m_validate=(XMLString::equals(flag,xmlconstants::XML_TRUE) || XMLString::equals(flag,xmlconstants::XML_ONE));\r
+}
+
+DynamicMetadataProvider::~DynamicMetadataProvider()
+{
+ // Each entity in the map is unique (no multimap semantics), so this is safe.
+ clearDescriptorIndex(true);
+ delete m_lock;
+}
+
+const EntityDescriptor* DynamicMetadataProvider::getEntityDescriptor(const char* name, bool strict) const
+{
+ // Check cache while holding the read lock.
+ const EntityDescriptor* entity = AbstractMetadataProvider::getEntityDescriptor(name, strict);
+ if (entity)
+ return entity;
+
+ Category& log = Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic");
+ log.info("resolving metadata for (%s)", name);
+
+ // Try resolving it.
+ auto_ptr<EntityDescriptor> entity2(resolve(name));
+
+ // Filter it, which may throw.
+ doFilters(*entity2.get());
+
+ log.info("caching resolved metadata for (%s)", name);
+
+ // Translate cacheDuration into validUntil.
+ if (entity2->getCacheDuration())
+ entity2->setValidUntil(time(NULL) + entity2->getCacheDurationEpoch());
+
+ // Upgrade our lock so we can cache the new metadata.
+ m_lock->unlock();
+ m_lock->wrlock();
+
+ // Notify observers.
+ emitChangeEvent();
+
+ // Make sure we clear out any existing copies, including stale metadata or if somebody snuck in.
+ index(entity2.release(), SAMLTIME_MAX, true);
+
+ // Downgrade back to a read lock.
+ m_lock->unlock();
+ m_lock->rdlock();
+
+ // Rinse and repeat.
+ return getEntityDescriptor(name, strict);
+}
+
+EntityDescriptor* DynamicMetadataProvider::resolve(const char* entityID) const
+{
+ try {\r
+ DOMDocument* doc=NULL;\r
+ auto_ptr_XMLCh widenit(entityID);\r
+ URLInputSource src(widenit.get());\r
+ Wrapper4InputSource dsrc(&src,false);\r
+ if (m_validate)\r
+ doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);\r
+ else\r
+ doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);\r
+\r
+ // Wrap the document for now.
+ XercesJanitor<DOMDocument> docjanitor(doc);
+
+ // Unmarshall objects, binding the document.
+ auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
+ docjanitor.release();
+
+ // Make sure it's metadata.
+ EntityDescriptor* entity = dynamic_cast<EntityDescriptor*>(xmlObject.get());
+ if (!entity) {
+ throw MetadataException(
+ "Root of metadata instance not recognized: $1", params(1,xmlObject->getElementQName().toString().c_str())
+ );
+ }
+ xmlObject.release();\r
+ return entity;\r
+ }\r
+ catch (XMLException& e) {\r
+ auto_ptr_char msg(e.getMessage());\r
+ Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic").error(\r
+ "Xerces error while resolving entityID (%s): %s", entityID, msg.get()\r
+ );\r
+ throw MetadataException(msg.get());\r
+ }\r
+ catch (exception& e) {\r
+ Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic").error(\r
+ "error while resolving entityID (%s): %s", entityID, e.what()\r
+ );\r
+ throw;\r
+ }\r
+}
namespace opensaml {
namespace saml2md {
SAML_DLLLOCAL PluginManager<MetadataProvider,string,const DOMElement*>::Factory XMLMetadataProviderFactory;
+ SAML_DLLLOCAL PluginManager<MetadataProvider,string,const DOMElement*>::Factory DynamicMetadataProviderFactory;
SAML_DLLLOCAL PluginManager<MetadataProvider,string,const DOMElement*>::Factory ChainingMetadataProviderFactory;
SAML_DLLLOCAL PluginManager<MetadataFilter,string,const DOMElement*>::Factory BlacklistMetadataFilterFactory;
SAML_DLLLOCAL PluginManager<MetadataFilter,string,const DOMElement*>::Factory WhitelistMetadataFilterFactory;
{
SAMLConfig& conf=SAMLConfig::getConfig();
conf.MetadataProviderManager.registerFactory(XML_METADATA_PROVIDER, XMLMetadataProviderFactory);
+ conf.MetadataProviderManager.registerFactory(DYNAMIC_METADATA_PROVIDER, DynamicMetadataProviderFactory);
conf.MetadataProviderManager.registerFactory(CHAINING_METADATA_PROVIDER, ChainingMetadataProviderFactory);
- conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.metadata.provider.XMLMetadata", XMLMetadataProviderFactory);
- conf.MetadataProviderManager.registerFactory("edu.internet2.middleware.shibboleth.common.provider.XMLMetadata", XMLMetadataProviderFactory);
}
void SAML_API opensaml::saml2md::registerMetadataFilters()