Dynamic metadata provider implementation.
authorcantor <cantor@fb386ef7-a10c-0410-8ebf-fd3f8e989ab0>
Wed, 29 Aug 2007 18:03:01 +0000 (18:03 +0000)
committercantor <cantor@fb386ef7-a10c-0410-8ebf-fd3f8e989ab0>
Wed, 29 Aug 2007 18:03:01 +0000 (18:03 +0000)
git-svn-id: https://svn.middleware.georgetown.edu/cpp-opensaml2/trunk@298 fb386ef7-a10c-0410-8ebf-fd3f8e989ab0

saml/Makefile.am
saml/saml.vcproj
saml/saml2/metadata/AbstractMetadataProvider.h
saml/saml2/metadata/DynamicMetadataProvider.h [new file with mode: 0644]
saml/saml2/metadata/MetadataProvider.h
saml/saml2/metadata/impl/AbstractMetadataProvider.cpp
saml/saml2/metadata/impl/ChainingMetadataProvider.cpp
saml/saml2/metadata/impl/DynamicMetadataProvider.cpp [new file with mode: 0644]
saml/saml2/metadata/impl/MetadataProvider.cpp

index d371504..4cfdd44 100644 (file)
@@ -83,6 +83,7 @@ saml2bindinclude_HEADERS = \
 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 \
@@ -135,6 +136,7 @@ libsaml_la_SOURCES = \
        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 \
index 1314ae8..76dd93f 100644 (file)
                                                        >\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
index 3506cac..806347f 100644 (file)
@@ -82,29 +82,32 @@ namespace opensaml {
              * 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;
diff --git a/saml/saml2/metadata/DynamicMetadataProvider.h b/saml/saml2/metadata/DynamicMetadataProvider.h
new file mode 100644 (file)
index 0000000..44b622b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  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__ */
index 6e2c6d4..2e9b4b9 100644 (file)
@@ -211,6 +211,9 @@ namespace opensaml {
         /** 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"
 
index 196962b..6508e58 100644 (file)
@@ -69,13 +69,26 @@ void AbstractMetadataProvider::emitChangeEvent() const
     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));
     }
     
@@ -120,7 +133,7 @@ void AbstractMetadataProvider::index(EntityDescriptor* site, time_t validUntil)
     }
 }
 
-void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUntil)
+void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUntil) const
 {
     if (validUntil < group->getValidUntilEpoch())
         group->setValidUntil(validUntil);
@@ -139,11 +152,13 @@ void AbstractMetadataProvider::index(EntitiesDescriptor* group, time_t validUnti
         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
index 25bc3db..1bcd092 100644 (file)
@@ -115,7 +115,7 @@ void ChainingMetadataProvider::unlock()
 
 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
diff --git a/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp b/saml/saml2/metadata/impl/DynamicMetadataProvider.cpp
new file mode 100644 (file)
index 0000000..a23308f
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ *  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
+}
index 152f994..62665a0 100644 (file)
@@ -38,6 +38,7 @@ using namespace std;
 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;
@@ -49,9 +50,8 @@ void SAML_API opensaml::saml2md::registerMetadataProviders()
 {
     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()