X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=saml%2Fsaml2%2Fmetadata%2Fimpl%2FXMLMetadataProvider.cpp;h=86c9601c9e5f90bbc2600feac705863037af6ea4;hb=3f107084066988f951c36f1671d5ef5b19e498a1;hp=bf359c93ec2ef0d5801f445151b4367be673c433;hpb=d6379bae77dd178313af9ec8e117a3dbd835ed0a;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp b/saml/saml2/metadata/impl/XMLMetadataProvider.cpp index bf359c9..86c9601 100644 --- a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/XMLMetadataProvider.cpp @@ -1,17 +1,21 @@ -/* - * Copyright 2001-2010 Internet2 +/** + * Licensed to the University Corporation for Advanced Internet + * Development, Inc. (UCAID) under one or more contributor license + * agreements. See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. * - * 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 + * UCAID licenses this file to you 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 + * 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. + * 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. */ /** @@ -25,17 +29,28 @@ #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataFilter.h" #include "saml2/metadata/AbstractMetadataProvider.h" +#include "saml2/metadata/DiscoverableMetadataProvider.h" #include +#include #include +#include #include +#include #include #include #include +#if defined(OPENSAML_LOG4SHIB) +# include +#elif defined(OPENSAML_LOG4CPP) +# include +#endif + using namespace opensaml::saml2md; using namespace xmltooling::logging; using namespace xmltooling; +using namespace boost; using namespace std; #if defined (_MSC_VER) @@ -46,26 +61,70 @@ using namespace std; namespace opensaml { namespace saml2md { - static const XMLCh minRefreshDelay[] = UNICODE_LITERAL_15(m,i,n,R,e,f,r,e,s,h,D,e,l,a,y); - static const XMLCh refreshDelayFactor[] = UNICODE_LITERAL_18(r,e,f,r,e,s,h,D,e,l,a,y,F,a,c,t,o,r); - - class SAML_DLLLOCAL XMLMetadataProvider : public AbstractMetadataProvider, public ReloadableXMLFile + class SAML_DLLLOCAL XMLMetadataProvider + : public AbstractMetadataProvider, public DiscoverableMetadataProvider, public ReloadableXMLFile { public: XMLMetadataProvider(const DOMElement* e); virtual ~XMLMetadataProvider() { shutdown(); - delete m_object; } void init() { - background_load(); - startup(); + try { + if (!m_id.empty()) { + string threadid("["); + threadid += m_id + ']'; + logging::NDC::push(threadid); + } + background_load(); + startup(); + } + catch (...) { + startup(); + if (!m_id.empty()) { + logging::NDC::pop(); + } + throw; + } + + if (!m_id.empty()) { + logging::NDC::pop(); + } + } + + const char* getId() const { + return m_id.c_str(); + } + + void outputStatus(ostream& os) const { + os << " 0) { + DateTime ts(m_lastUpdate); + ts.parseDateTime(); + auto_ptr_char timestamp(ts.getFormattedString()); + os << " lastUpdate='" << timestamp.get() << "'"; + } + + if (!m_local && m_reloadInterval > 0) { + os << " reloadInterval='" << m_reloadInterval << "'"; + } + + os << "/>"; } const XMLObject* getMetadata() const { - return m_object; + return m_object.get(); } protected: @@ -77,7 +136,8 @@ namespace opensaml { void index(time_t& validUntil); time_t computeNextRefresh(); - XMLObject* m_object; + scoped_ptr m_object; + bool m_discoveryFeed,m_dropDOM; double m_refreshDelayFactor; unsigned int m_backoffFactor; time_t m_minRefreshDelay,m_maxRefreshDelay,m_lastValidUntil; @@ -88,6 +148,10 @@ namespace opensaml { return new XMLMetadataProvider(e); } + static const XMLCh discoveryFeed[] = UNICODE_LITERAL_13(d,i,s,c,o,v,e,r,y,F,e,e,d); + static const XMLCh dropDOM[] = UNICODE_LITERAL_7(d,r,o,p,D,O,M); + static const XMLCh minRefreshDelay[] = UNICODE_LITERAL_15(m,i,n,R,e,f,r,e,s,h,D,e,l,a,y); + static const XMLCh refreshDelayFactor[] = UNICODE_LITERAL_18(r,e,f,r,e,s,h,D,e,l,a,y,F,a,c,t,o,r); }; }; @@ -96,12 +160,16 @@ namespace opensaml { #endif XMLMetadataProvider::XMLMetadataProvider(const DOMElement* e) - : AbstractMetadataProvider(e), ReloadableXMLFile(e, Category::getInstance(SAML_LOGCAT".MetadataProvider.XML"), false), - m_object(nullptr), m_refreshDelayFactor(0.75), m_backoffFactor(1), m_minRefreshDelay(600), + : MetadataProvider(e), AbstractMetadataProvider(e), DiscoverableMetadataProvider(e), + ReloadableXMLFile(e, Category::getInstance(SAML_LOGCAT".MetadataProvider.XML"), false), + m_discoveryFeed(XMLHelper::getAttrBool(e, true, discoveryFeed)), + m_dropDOM(XMLHelper::getAttrBool(e, true, dropDOM)), + m_refreshDelayFactor(0.75), m_backoffFactor(1), + m_minRefreshDelay(XMLHelper::getAttrInt(e, 600, minRefreshDelay)), m_maxRefreshDelay(m_reloadInterval), m_lastValidUntil(SAMLTIME_MAX) { if (!m_local && m_maxRefreshDelay) { - const XMLCh* setting = e ? e->getAttributeNS(nullptr, refreshDelayFactor) : NULL; + const XMLCh* setting = e->getAttributeNS(nullptr, refreshDelayFactor); if (setting && *setting) { auto_ptr_char delay(setting); m_refreshDelayFactor = atof(delay.get()); @@ -110,25 +178,20 @@ XMLMetadataProvider::XMLMetadataProvider(const DOMElement* e) m_refreshDelayFactor = 0.75; } } - setting = e ? e->getAttributeNS(nullptr, minRefreshDelay) : NULL; - if (setting && *setting) { - m_minRefreshDelay = XMLString::parseInt(setting); - if (m_minRefreshDelay == 0) { - m_log.error("invalid minRefreshDelay setting, using default"); - m_minRefreshDelay = 600; - } - else if (m_minRefreshDelay > m_maxRefreshDelay) { - m_log.error("minRefreshDelay setting exceeds maxRefreshDelay/refreshInterval setting, lowering to match it"); - m_minRefreshDelay = m_maxRefreshDelay; - } + + if (m_minRefreshDelay > m_maxRefreshDelay) { + m_log.warn("minRefreshDelay setting exceeds maxRefreshDelay/reloadInterval setting, lowering to match it"); + m_minRefreshDelay = m_maxRefreshDelay; } } } pair XMLMetadataProvider::load(bool backup) { - // Lower the refresh rate in case of an error. - m_reloadInterval = m_minRefreshDelay; + if (!backup) { + // Lower the refresh rate in case of an error. + m_reloadInterval = m_minRefreshDelay; + } // Call the base class to load/parse the appropriate XML resource. pair raw = ReloadableXMLFile::load(backup); @@ -137,7 +200,7 @@ pair XMLMetadataProvider::load(bool backup) XercesJanitor docjanitor(raw.first ? raw.second->getOwnerDocument() : nullptr); // Unmarshall objects, binding the document. - auto_ptr xmlObject(XMLObjectBuilder::buildOneFromElement(raw.second, true)); + scoped_ptr xmlObject(XMLObjectBuilder::buildOneFromElement(raw.second, true)); docjanitor.release(); if (!dynamic_cast(xmlObject.get()) && !dynamic_cast(xmlObject.get())) @@ -149,11 +212,17 @@ pair XMLMetadataProvider::load(bool backup) try { SchemaValidators.validate(xmlObject.get()); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.error("metadata intance failed manual validation checking: %s", ex.what()); throw MetadataException("Metadata instance failed manual validation checking."); } + const TimeBoundSAMLObject* validityCheck = dynamic_cast(xmlObject.get()); + if (!validityCheck || !validityCheck->isValid()) { + m_log.error("metadata instance was invalid at time of acquisition"); + throw MetadataException("Metadata instance was invalid at time of acquisition."); + } + // This is the best place to take a backup, since it's superficially "correct" metadata. string backupKey; if (!backup && !m_backing.empty()) { @@ -165,16 +234,16 @@ pair XMLMetadataProvider::load(bool backup) ofstream backer(backupKey.c_str()); backer << *(raw.second->getOwnerDocument()); } - catch (exception& ex) { + catch (std::exception& ex) { m_log.crit("exception while backing up metadata: %s", ex.what()); backupKey.erase(); } } try { - doFilters(*xmlObject.get()); + doFilters(*xmlObject); } - catch (exception&) { + catch (std::exception&) { if (!backupKey.empty()) remove(backupKey.c_str()); throw; @@ -186,28 +255,33 @@ pair XMLMetadataProvider::load(bool backup) remove(m_backing.c_str()); if (rename(backupKey.c_str(), m_backing.c_str()) != 0) m_log.crit("unable to rename metadata backup file"); + preserveCacheTag(); } - xmlObject->releaseThisAndChildrenDOM(); - xmlObject->setDocument(nullptr); + if (m_dropDOM) { + xmlObject->releaseThisAndChildrenDOM(); + xmlObject->setDocument(nullptr); + } // Swap it in after acquiring write lock if necessary. if (m_lock) m_lock->wrlock(); SharedLock locker(m_lock, false); bool changed = m_object!=nullptr; - delete m_object; - m_object = xmlObject.release(); + m_object.swap(xmlObject); m_lastValidUntil = SAMLTIME_MAX; index(m_lastValidUntil); + if (m_discoveryFeed) + generateFeed(); if (changed) emitChangeEvent(); + m_lastUpdate = time(nullptr); // Tracking cacheUntil through the tree is TBD, but // validUntil is the tightest interval amongst the children. - // If a remote resource, adjust the reload interval. - if (!backup) { + // If a remote resource that's monitored, adjust the reload interval. + if (!backup && !m_local && m_lock) { m_backoffFactor = 1; m_reloadInterval = computeNextRefresh(); m_log.info("adjusted reload interval to %d seconds", m_reloadInterval); @@ -226,41 +300,32 @@ pair XMLMetadataProvider::background_load() if (ex == HTTPResponse::XMLTOOLING_HTTP_STATUS_NOTMODIFIED) { // Unchanged document, so re-establish previous refresh interval. m_reloadInterval = computeNextRefresh(); - m_log.info("adjusted reload interval to %d seconds", m_reloadInterval); + m_log.info("remote resource (%s) unchanged, adjusted reload interval to %u seconds", m_source.c_str(), m_reloadInterval); } else { // Any other status code, just treat as an error. m_reloadInterval = m_minRefreshDelay * m_backoffFactor++; if (m_reloadInterval > m_maxRefreshDelay) m_reloadInterval = m_maxRefreshDelay; - m_log.warn("adjusted reload interval to %d seconds", m_reloadInterval); + m_log.warn("adjusted reload interval to %u seconds", m_reloadInterval); } if (!m_loaded && !m_backing.empty()) return load(true); throw; } - catch (exception&) { - m_reloadInterval = m_minRefreshDelay * m_backoffFactor++; - if (m_reloadInterval > m_maxRefreshDelay) - m_reloadInterval = m_maxRefreshDelay; - m_log.warn("adjusted reload interval to %d seconds", m_reloadInterval); - if (!m_loaded && !m_backing.empty()) - return load(true); + catch (std::exception&) { + if (!m_local) { + m_reloadInterval = m_minRefreshDelay * m_backoffFactor++; + if (m_reloadInterval > m_maxRefreshDelay) + m_reloadInterval = m_maxRefreshDelay; + m_log.warn("adjusted reload interval to %u seconds", m_reloadInterval); + if (!m_loaded && !m_backing.empty()) + return load(true); + } throw; } } -void XMLMetadataProvider::index(time_t& validUntil) -{ - clearDescriptorIndex(); - EntitiesDescriptor* group=dynamic_cast(m_object); - if (group) { - indexGroup(group, validUntil); - return; - } - indexEntity(dynamic_cast(m_object), validUntil); -} - time_t XMLMetadataProvider::computeNextRefresh() { time_t now = time(nullptr); @@ -272,7 +337,7 @@ time_t XMLMetadataProvider::computeNextRefresh() else { // Compute the smaller of the validUntil / cacheDuration constraints. time_t ret = m_lastValidUntil - now; - const CacheableSAMLObject* cacheable = dynamic_cast(m_object); + const CacheableSAMLObject* cacheable = dynamic_cast(m_object.get()); if (cacheable && cacheable->getCacheDuration()) ret = min(ret, cacheable->getCacheDurationEpoch()); @@ -288,3 +353,14 @@ time_t XMLMetadataProvider::computeNextRefresh() return ret; } } + +void XMLMetadataProvider::index(time_t& validUntil) +{ + clearDescriptorIndex(); + EntitiesDescriptor* group = dynamic_cast(m_object.get()); + if (group) { + indexGroup(group, validUntil); + return; + } + indexEntity(dynamic_cast(m_object.get()), validUntil); +}