X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=saml%2Fsaml2%2Fmetadata%2Fimpl%2FDynamicMetadataProvider.cpp;h=c3962ec7638a4f5a8e4d728a4cb2589065026878;hb=e9554c255ad3c91c7c4976e7a1a54905903e66a2;hp=2db9a48e8d809acdab9036a6a9e630bf77deadbf;hpb=529b003774ec45cad19910b845a52a70d273043d;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp b/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp index 2db9a48..c3962ec 100644 --- a/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Internet2 + * Copyright 2001-2010 Internet2 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +26,13 @@ #include "saml2/metadata/DynamicMetadataProvider.h" #include -#include #include #include +#include +#include +#include #include +#include using namespace opensaml::saml2md; using namespace xmltooling::logging; @@ -55,9 +58,9 @@ namespace opensaml { DynamicMetadataProvider::DynamicMetadataProvider(const DOMElement* e) : AbstractMetadataProvider(e), m_maxCacheDuration(28800), m_lock(RWLock::create()) { - const XMLCh* flag=e ? e->getAttributeNS(NULL,validate) : NULL; + const XMLCh* flag=e ? e->getAttributeNS(nullptr,validate) : nullptr; m_validate=(XMLString::equals(flag,xmlconstants::XML_TRUE) || XMLString::equals(flag,xmlconstants::XML_ONE)); - flag = e ? e->getAttributeNS(NULL,maxCacheDuration) : NULL; + flag = e ? e->getAttributeNS(nullptr,maxCacheDuration) : nullptr; if (flag && *flag) { m_maxCacheDuration = XMLString::parseInt(flag); if (m_maxCacheDuration == 0) @@ -72,12 +75,38 @@ DynamicMetadataProvider::~DynamicMetadataProvider() delete m_lock; } +const XMLObject* DynamicMetadataProvider::getMetadata() const +{ + throw MetadataException("getMetadata operation not implemented on this provider."); +} + +Lockable* DynamicMetadataProvider::lock() +{ + m_lock->rdlock(); + return this; +} + +void DynamicMetadataProvider::unlock() +{ + m_lock->unlock(); +} + +void DynamicMetadataProvider::init() +{ +} + pair DynamicMetadataProvider::getEntityDescriptor(const Criteria& criteria) const { - // Check cache while holding the read lock. pair entity = AbstractMetadataProvider::getEntityDescriptor(criteria); - if (entity.first) // even if the role isn't found, we're done - return entity; + if (entity.first) { + // Check to see if we're within the caching interval. + cachemap_t::iterator cit = m_cacheMap.find(entity.first->getEntityID()); + if (cit != m_cacheMap.end()) { + if (time(nullptr) <= cit->second) + return entity; + m_cacheMap.erase(cit); + } + } string name; if (criteria.entityID_ascii) @@ -86,13 +115,17 @@ pair DynamicMetadataProvider::get auto_ptr_char temp(criteria.entityID_unicode); name = temp.get(); } - else if (criteria.artifact) + else if (criteria.artifact) { name = criteria.artifact->getSource(); + } else return entity; Category& log = Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic"); - log.info("resolving metadata for (%s)", name.c_str()); + if (entity.first) + log.info("metadata for (%s) is beyond caching interval, attempting to refresh", name.c_str()); + else + log.info("resolving metadata for (%s)", name.c_str()); try { // Try resolving it. @@ -100,34 +133,34 @@ pair DynamicMetadataProvider::get // Verify the entityID. if (criteria.entityID_unicode && !XMLString::equals(criteria.entityID_unicode, entity2->getEntityID())) { - Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic").error("metadata instance did not match expected entityID"); + log.error("metadata instance did not match expected entityID"); return entity; } else { auto_ptr_XMLCh temp2(name.c_str()); if (!XMLString::equals(temp2.get(), entity2->getEntityID())) { - Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic").error("metadata instance did not match expected entityID"); + log.error("metadata instance did not match expected entityID"); return entity; } } + // Preprocess the metadata (even if we schema-validated). + try { + SchemaValidators.validate(entity2.get()); + } + catch (exception& ex) { + log.error("metadata intance failed manual validation checking: %s", ex.what()); + throw MetadataException("Metadata instance failed manual validation checking."); + } + // Filter it, which may throw. doFilters(*entity2.get()); - log.info("caching resolved metadata for (%s)", name.c_str()); + time_t now = time(nullptr); + if (entity2->getValidUntil() && entity2->getValidUntilEpoch() < now + 60) + throw MetadataException("Metadata was already invalid at the time of retrieval."); - // Translate cacheDuration into validUntil. - time_t exp = m_maxCacheDuration; - if (entity2->getCacheDuration()) - exp = min(m_maxCacheDuration, entity2->getCacheDurationEpoch()); - exp += time(NULL); - if (entity2->getValidUntil()) { - if (exp < entity2->getValidUntilEpoch()) - entity2->setValidUntil(exp); - } - else { - entity2->setValidUntil(exp); - } + log.info("caching resolved metadata for (%s)", name.c_str()); // Upgrade our lock so we can cache the new metadata. m_lock->unlock(); @@ -136,6 +169,13 @@ pair DynamicMetadataProvider::get // Notify observers. emitChangeEvent(); + // Note the cache duration. + time_t cacheExp = m_maxCacheDuration; + if (entity2->getCacheDuration()) + cacheExp = min(m_maxCacheDuration, entity2->getCacheDurationEpoch()); + cacheExp = max(cacheExp, 60); + m_cacheMap[entity2->getEntityID()] = time(nullptr) + cacheExp; + // Make sure we clear out any existing copies, including stale metadata or if somebody snuck in. index(entity2.release(), SAMLTIME_MAX, true); @@ -144,9 +184,17 @@ pair DynamicMetadataProvider::get m_lock->rdlock(); } catch (exception& e) { - Category::getInstance(SAML_LOGCAT".MetadataProvider.Dynamic").error( - "error while resolving entityID (%s): %s", name.c_str(), e.what() - ); + log.error("error while resolving entityID (%s): %s", name.c_str(), e.what()); + // This will return entries that are beyond their cache period, + // but not beyond their validity unless that criteria option was set. + // If it is a cache-expired entry, bump the cache period to prevent retries. + if (entity.first) { + time_t cacheExp = 600; + if (entity.first->getCacheDuration()) + cacheExp = min(m_maxCacheDuration, entity.first->getCacheDurationEpoch()); + cacheExp = max(cacheExp, 60); + m_cacheMap[entity.first->getEntityID()] = time(nullptr) + cacheExp; + } return entity; } @@ -157,17 +205,19 @@ pair DynamicMetadataProvider::get EntityDescriptor* DynamicMetadataProvider::resolve(const Criteria& criteria) const { string name; - if (criteria.entityID_ascii) + if (criteria.entityID_ascii) { name = criteria.entityID_ascii; + } else if (criteria.entityID_unicode) { auto_ptr_char temp(criteria.entityID_unicode); name = temp.get(); } - else if (criteria.artifact) - name = criteria.artifact->getSource(); + else if (criteria.artifact) { + throw MetadataException("Unable to resolve metadata dynamically from an artifact."); + } try { - DOMDocument* doc=NULL; + DOMDocument* doc=nullptr; auto_ptr_XMLCh widenit(name.c_str()); URLInputSource src(widenit.get()); Wrapper4InputSource dsrc(&src,false);