SSPCPP-616 - clean up concatenated string literals
[shibboleth/cpp-opensaml.git] / saml / saml2 / metadata / impl / AbstractMetadataProvider.cpp
index d642634..f2cca92 100644 (file)
 #include "saml2/metadata/MetadataCredentialContext.h"
 #include "saml2/metadata/MetadataCredentialCriteria.h"
 
+#include <boost/iterator/indirect_iterator.hpp>
+#include <boost/lambda/bind.hpp>
+#include <boost/lambda/if.hpp>
+#include <boost/lambda/lambda.hpp>
 #include <xercesc/util/XMLUniDefs.hpp>
 #include <xmltooling/logging.h>
 #include <xmltooling/XMLToolingConfig.h>
 #include <xmltooling/security/Credential.h>
 #include <xmltooling/security/KeyInfoResolver.h>
 #include <xmltooling/security/SecurityHelper.h>
+#include <xmltooling/util/DateTime.h>
 #include <xmltooling/util/Threads.h>
 #include <xmltooling/util/XMLHelper.h>
 
 using namespace opensaml::saml2md;
 using namespace xmltooling::logging;
 using namespace xmltooling;
+using namespace boost::lambda;
+using namespace boost;
 using namespace std;
 using opensaml::SAMLArtifact;
 
 static const XMLCh _KeyInfoResolver[] = UNICODE_LITERAL_15(K,e,y,I,n,f,o,R,e,s,o,l,v,e,r);
-static const XMLCh type[] =             UNICODE_LITERAL_4(t,y,p,e);
+static const XMLCh _type[] =            UNICODE_LITERAL_4(t,y,p,e);
 
 AbstractMetadataProvider::AbstractMetadataProvider(const DOMElement* e)
-    : ObservableMetadataProvider(e), m_resolver(nullptr), m_credentialLock(nullptr)
+    : ObservableMetadataProvider(e), m_lastUpdate(0),  m_resolver(nullptr), m_credentialLock(Mutex::create())
 {
     e = XMLHelper::getFirstChildElement(e, _KeyInfoResolver);
     if (e) {
-        string t = XMLHelper::getAttrString(e, nullptr, type);
-        if (!t.empty())
-            m_resolver = XMLToolingConfig::getConfig().KeyInfoResolverManager.newPlugin(t.c_str(), e);
-        else
+        string t = XMLHelper::getAttrString(e, nullptr, _type);
+        if (!t.empty()) {
+            m_resolverWrapper.reset(XMLToolingConfig::getConfig().KeyInfoResolverManager.newPlugin(t.c_str(), e));
+            m_resolver = m_resolverWrapper.get();
+        }
+        else {
             throw UnknownExtensionException("<KeyInfoResolver> element found with no type attribute");
+        }
     }
-    m_credentialLock = Mutex::create();
 }
 
 AbstractMetadataProvider::~AbstractMetadataProvider()
 {
     for (credmap_t::iterator c = m_credentialMap.begin(); c!=m_credentialMap.end(); ++c)
         for_each(c->second.begin(), c->second.end(), xmltooling::cleanup<Credential>());
-    delete m_credentialLock;
-    delete m_resolver;
+}
+
+void AbstractMetadataProvider::outputStatus(ostream& os) const
+{
+    os << "<MetadataProvider";
+
+    if (getId() && *getId()) {
+        os << " id='" << getId() << "'";
+    }
+
+    if (m_lastUpdate > 0) {
+        DateTime ts(m_lastUpdate);
+        ts.parseDateTime();
+        auto_ptr_char timestamp(ts.getFormattedString());
+        os << " lastUpdate='" << timestamp.get() << "'";
+    }
+
+    os << "/>";
 }
 
 void AbstractMetadataProvider::emitChangeEvent() const
@@ -79,6 +104,14 @@ void AbstractMetadataProvider::emitChangeEvent() const
     ObservableMetadataProvider::emitChangeEvent();
 }
 
+void AbstractMetadataProvider::emitChangeEvent(const EntityDescriptor& entity) const
+{
+    for (credmap_t::iterator c = m_credentialMap.begin(); c!=m_credentialMap.end(); ++c)
+        for_each(c->second.begin(), c->second.end(), xmltooling::cleanup<Credential>());
+    m_credentialMap.clear();
+    ObservableMetadataProvider::emitChangeEvent(entity);
+}
+
 void AbstractMetadataProvider::indexEntity(EntityDescriptor* site, time_t& validUntil, bool replace) const
 {
     // If child expires later than input, reset child, otherwise lower input to match.
@@ -90,9 +123,21 @@ void AbstractMetadataProvider::indexEntity(EntityDescriptor* site, time_t& valid
     auto_ptr_char id(site->getEntityID());
     if (id.get()) {
         if (replace) {
-            m_sites.erase(id.get());
+            // The data structure here needs work.
+            // We have to find all the sites stored against the replaced ID. Then we have to
+            // search for those sites in the entire set of sites tracked by the sources map and
+            // remove them from both places.
+            set<const EntityDescriptor*> existingSites;
+            pair<sitemap_t::iterator,sitemap_t::iterator> existingRange = m_sites.equal_range(id.get());
+            static pair<set<const EntityDescriptor*>::iterator,bool> (set<const EntityDescriptor*>::* ins)(const EntityDescriptor* const &) =
+                &set<const EntityDescriptor*>::insert;
+            for_each(
+                existingRange.first, existingRange.second,
+                lambda::bind(ins, boost::ref(existingSites), lambda::bind(&sitemap_t::value_type::second, _1))
+                );
+            m_sites.erase(existingRange.first, existingRange.second);
             for (sitemap_t::iterator s = m_sources.begin(); s != m_sources.end();) {
-                if (s->second == site) {
+                if (existingSites.count(s->second) > 0) {
                     sitemap_t::iterator temp = s;
                     ++s;
                     m_sources.erase(temp);
@@ -214,7 +259,7 @@ const EntitiesDescriptor* AbstractMetadataProvider::getEntitiesDescriptor(const
             return i->second;
     
     if (range.first != range.second) {
-        Category& log = Category::getInstance(SAML_LOGCAT".MetadataProvider");
+        Category& log = Category::getInstance(SAML_LOGCAT ".MetadataProvider");
         if (strict) {
             log.warn("ignored expired metadata group (%s)", range.first->first.c_str());
         }
@@ -254,7 +299,7 @@ pair<const EntityDescriptor*,const RoleDescriptor*> AbstractMetadataProvider::ge
     }
     
     if (!result.first && range.first!=range.second) {
-        Category& log = Category::getInstance(SAML_LOGCAT".MetadataProvider");
+        Category& log = Category::getInstance(SAML_LOGCAT ".MetadataProvider");
         if (criteria.validOnly) {
             log.warn("ignored expired metadata instance for (%s)", range.first->first.c_str());
         }
@@ -283,9 +328,9 @@ const Credential* AbstractMetadataProvider::resolve(const CredentialCriteria* cr
     const credmap_t::mapped_type& creds = resolveCredentials(metacrit->getRole());
 
     for (credmap_t::mapped_type::const_iterator c = creds.begin(); c!=creds.end(); ++c)
-        if (metacrit->matches(*(*c)))
-            return *c;
-    return nullptr;
+       if (metacrit->matches(*(*c)))
+       return *c;
+return nullptr;
 }
 
 vector<const Credential*>::size_type AbstractMetadataProvider::resolve(
@@ -299,27 +344,31 @@ vector<const Credential*>::size_type AbstractMetadataProvider::resolve(
     Lock lock(m_credentialLock);
     const credmap_t::mapped_type& creds = resolveCredentials(metacrit->getRole());
 
-    for (credmap_t::mapped_type::const_iterator c = creds.begin(); c!=creds.end(); ++c)
-        if (metacrit->matches(*(*c)))
-            results.push_back(*c);
+   for (credmap_t::mapped_type::const_iterator c = creds.begin(); c!=creds.end(); ++c)
+       if (metacrit->matches(*(*c)))
+           results.push_back(*c); 
     return results.size();
 }
 
 const AbstractMetadataProvider::credmap_t::mapped_type& AbstractMetadataProvider::resolveCredentials(const RoleDescriptor& role) const
 {
     credmap_t::const_iterator i = m_credentialMap.find(&role);
-    if (i!=m_credentialMap.end())
+    if (i != m_credentialMap.end())
         return i->second;
 
     const KeyInfoResolver* resolver = m_resolver ? m_resolver : XMLToolingConfig::getConfig().getKeyInfoResolver();
     const vector<KeyDescriptor*>& keys = role.getKeyDescriptors();
     AbstractMetadataProvider::credmap_t::mapped_type& resolved = m_credentialMap[&role];
-    for (vector<KeyDescriptor*>::const_iterator k = keys.begin(); k!=keys.end(); ++k) {
-        if ((*k)->getKeyInfo()) {
-            auto_ptr<MetadataCredentialContext> mcc(new MetadataCredentialContext(*(*k)));
-            Credential* c = resolver->resolve(mcc.get());
-            mcc.release();
-            resolved.push_back(c);
+    for (indirect_iterator<vector<KeyDescriptor*>::const_iterator> k = make_indirect_iterator(keys.begin());
+            k != make_indirect_iterator(keys.end()); ++k) {
+        if (k->getKeyInfo()) {
+            auto_ptr<MetadataCredentialContext> mcc(new MetadataCredentialContext(*k));
+            auto_ptr<Credential> c(resolver->resolve(mcc.get()));
+            if (c.get()) {
+                mcc.release();  // this API sucks, the object is now owned by the Credential
+                resolved.push_back(c.get());
+                c.release();
+            }
         }
     }
     return resolved;