X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=saml%2Fsaml2%2Fmetadata%2Fimpl%2FXMLMetadataProvider.cpp;h=5462564bff65ebe62135c2f9d16ff961e1f77886;hb=b83476f25f2f38fd3b0f36ed95c9a73b7c9b0eac;hp=adcdee8dd802f6809bb94b9a69e759969f96d184;hpb=ec8536a30d9adac2b7fc870405ee8f8482e249a6;p=shibboleth%2Fcpp-opensaml.git diff --git a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp b/saml/saml2/metadata/impl/XMLMetadataProvider.cpp index adcdee8..5462564 100644 --- a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/XMLMetadataProvider.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. @@ -21,12 +21,16 @@ */ #include "internal.h" +#include "binding/SAMLArtifact.h" #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataFilter.h" #include "saml2/metadata/AbstractMetadataProvider.h" +#include #include #include +#include +#include using namespace opensaml::saml2md; using namespace xmltooling::logging; @@ -41,23 +45,20 @@ using namespace std; namespace opensaml { namespace saml2md { - static const XMLCh requireValidUntil[] = UNICODE_LITERAL_17(r,e,q,u,i,r,e,V,a,l,i,d,U,n,t,i,l); - class SAML_DLLLOCAL XMLMetadataProvider : public AbstractMetadataProvider, public ReloadableXMLFile { public: XMLMetadataProvider(const DOMElement* e) : AbstractMetadataProvider(e), ReloadableXMLFile(e, Category::getInstance(SAML_LOGCAT".MetadataProvider.XML")), - m_object(NULL), m_requireValidUntil(false) { - const XMLCh* flag = e ? e->getAttributeNS(NULL,requireValidUntil) : NULL; - m_requireValidUntil = (flag && (*flag == chLatin_t || *flag == chDigit_1)); + m_object(NULL), m_maxCacheDuration(m_reloadInterval) { } virtual ~XMLMetadataProvider() { + shutdown(); delete m_object; } void init() { - load(); // guarantees an exception or the metadata is loaded + background_load(); // guarantees an exception or the metadata is loaded } const XMLObject* getMetadata() const { @@ -65,14 +66,14 @@ namespace opensaml { } protected: - pair load(); + pair background_load(); private: using AbstractMetadataProvider::index; void index(); XMLObject* m_object; - bool m_requireValidUntil; + time_t m_maxCacheDuration; }; MetadataProvider* SAML_DLLLOCAL XMLMetadataProviderFactory(const DOMElement* const & e) @@ -87,8 +88,11 @@ namespace opensaml { #pragma warning( pop ) #endif -pair XMLMetadataProvider::load() +pair XMLMetadataProvider::background_load() { + // Turn off auto-backup so we can filter first. + m_backupIndicator = false; + // Load from source using base class. pair raw = ReloadableXMLFile::load(); @@ -104,24 +108,73 @@ pair XMLMetadataProvider::load() "Root of metadata instance not recognized: $1", params(1,xmlObject->getElementQName().toString().c_str()) ); - if (m_requireValidUntil) { - const TimeBoundSAMLObject* tbo = dynamic_cast(xmlObject.get()); - if (!tbo || tbo->getValidUntil() == NULL) - throw MetadataException("Root of metadata instance does not have validUntil atttribute."); + // Preprocess the metadata (even if we schema-validated). + try { + SchemaValidators.validate(xmlObject.get()); + } + catch (exception& ex) { + m_log.error("metadata intance failed manual validation checking: %s", ex.what()); + throw MetadataException("Metadata instance failed manual validation checking."); + } + + // If the backup indicator is flipped, then this was a remote load and we need a backup. + // This is the best place to take a backup, since it's superficially "correct" metadata. + string backupKey; + if (m_backupIndicator) { + // We compute a random filename extension to the "real" location. + SAMLConfig::getConfig().generateRandomBytes(backupKey, 2); + backupKey = m_backing + '.' + SAMLArtifact::toHex(backupKey); + m_log.debug("backing up remote metadata resource to (%s)", backupKey.c_str()); + try { + ofstream backer(backupKey.c_str()); + backer << *raw.second->getOwnerDocument(); + } + catch (exception& ex) { + m_log.crit("exception while backing up metadata: %s", ex.what()); + backupKey.erase(); + } + } + + try { + doFilters(*xmlObject.get()); + } + catch (exception&) { + if (!backupKey.empty()) + remove(backupKey.c_str()); + throw; + } + + if (!backupKey.empty()) { + m_log.debug("committing backup file to permanent location (%s)", m_backing.c_str()); + Locker locker(getBackupLock()); + remove(m_backing.c_str()); + if (rename(backupKey.c_str(), m_backing.c_str()) != 0) + m_log.crit("unable to rename metadata backup file"); } - // Preprocess the metadata. - doFilters(*xmlObject.get()); xmlObject->releaseThisAndChildrenDOM(); xmlObject->setDocument(NULL); - // Swap it in. + // Swap it in after acquiring write lock if necessary. + if (m_lock) + m_lock->wrlock(); + SharedLock locker(m_lock, false); bool changed = m_object!=NULL; delete m_object; m_object = xmlObject.release(); index(); if (changed) emitChangeEvent(); + + // If a remote resource, adjust the reload interval if cacheDuration is set. + if (!m_local) { + const CacheableSAMLObject* cacheable = dynamic_cast(m_object); + if (cacheable && cacheable->getCacheDuration() && cacheable->getCacheDurationEpoch() < m_maxCacheDuration) + m_reloadInterval = cacheable->getCacheDurationEpoch(); + else + m_reloadInterval = m_maxCacheDuration; + } + return make_pair(false,(DOMElement*)NULL); } @@ -133,6 +186,5 @@ void XMLMetadataProvider::index() AbstractMetadataProvider::index(group, SAMLTIME_MAX); return; } - EntityDescriptor* site=dynamic_cast(m_object); - AbstractMetadataProvider::index(site, SAMLTIME_MAX); + AbstractMetadataProvider::index(dynamic_cast(m_object), SAMLTIME_MAX); }