Metadata filters, filter auto-registration, and unit tests.
authorScott Cantor <cantor.2@osu.edu>
Sun, 16 Jul 2006 21:18:40 +0000 (21:18 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 16 Jul 2006 21:18:40 +0000 (21:18 +0000)
15 files changed:
saml/Makefile.am
saml/SAMLConfig.cpp
saml/SAMLConfig.h
saml/saml.vcproj
saml/saml2/metadata/MetadataFilter.h
saml/saml2/metadata/MetadataProvider.h
saml/saml2/metadata/impl/BlacklistMetadataFilter.cpp [new file with mode: 0644]
saml/saml2/metadata/impl/FilesystemMetadataProvider.cpp
saml/saml2/metadata/impl/MetadataProvider.cpp
saml/saml2/metadata/impl/WhitelistMetadataFilter.cpp [new file with mode: 0644]
samltest/Makefile.am
samltest/data/saml2/metadata/FilesystemMetadataProvider.xml [new file with mode: 0644]
samltest/data/saml2/metadata/FilesystemWithBlacklists.xml [new file with mode: 0644]
samltest/data/saml2/metadata/FilesystemWithWhitelists.xml [new file with mode: 0644]
samltest/saml2/metadata/FilesystemMetadataProviderTest.h

index e982a79..3a215c0 100644 (file)
@@ -60,10 +60,12 @@ libsaml_la_SOURCES = \
        saml2/core/impl/Assertions20SchemaValidators.cpp \
        saml2/core/impl/Protocols20Impl.cpp \
        saml2/core/impl/Protocols20SchemaValidators.cpp \
+       saml2/metadata/impl/BlacklistMetadataFilter.cpp \
        saml2/metadata/impl/FilesystemMetadataProvider.cpp \
        saml2/metadata/impl/MetadataImpl.cpp \
        saml2/metadata/impl/MetadataProvider.cpp \
        saml2/metadata/impl/MetadataSchemaValidators.cpp \
+       saml2/metadata/impl/WhitelistMetadataFilter.cpp \
        signature/ContentReference.cpp \
        signature/SignatureProfileValidator.cpp \
        util/SAMLConstants.cpp
index 547526d..d17142b 100644 (file)
@@ -29,6 +29,7 @@
 #include "saml1/core/Protocols.h"
 #include "saml2/core/Protocols.h"
 #include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
 #include "util/SAMLConstants.h"
 
 #include <xmltooling/XMLToolingConfig.h>
@@ -78,6 +79,7 @@ bool SAMLInternalConfig::init()
     saml2p::registerProtocolClasses();
     saml2md::registerMetadataClasses();
     saml2md::registerMetadataProviders();
+    saml2md::registerMetadataFilters();
 
     log.info("library initialization complete");
     return true;
index bfd0a30..dca8f15 100644 (file)
@@ -24,7 +24,6 @@
 #define __saml_config_h__\r
 \r
 #include <saml/base.h>\r
-#include <saml/saml2/metadata/MetadataProvider.h>\r
 \r
 #include <xmltooling/PluginManager.h>\r
 #include <xmltooling/unicode.h>\r
  */\r
 namespace opensaml {\r
 \r
+    namespace saml2md {\r
+        class SAML_API MetadataProvider;\r
+        class SAML_API MetadataFilter;\r
+    };\r
+\r
+#if defined (_MSC_VER)\r
+    #pragma warning( push )\r
+    #pragma warning( disable : 4250 4251 )\r
+#endif\r
+\r
     /**\r
      * Singleton object that manages library startup/shutdown.configuration.\r
      */\r
@@ -110,6 +119,10 @@ namespace opensaml {
         SAMLConfig() {}\r
     };\r
 \r
+#if defined (_MSC_VER)\r
+    #pragma warning( pop )\r
+#endif\r
+    \r
 };\r
 \r
 #endif /* __saml_config_h__ */\r
index aad767a..0a61744 100644 (file)
                                                Name="impl"\r
                                                >\r
                                                <File\r
+                                                       RelativePath=".\saml2\metadata\impl\BlacklistMetadataFilter.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml2\metadata\impl\FilesystemMetadataProvider.cpp"\r
                                                        >\r
                                                </File>\r
                                                        RelativePath=".\saml2\metadata\impl\MetadataSchemaValidators.cpp"\r
                                                        >\r
                                                </File>\r
+                                               <File\r
+                                                       RelativePath=".\saml2\metadata\impl\WhitelistMetadataFilter.cpp"\r
+                                                       >\r
+                                               </File>\r
                                        </Filter>\r
                                </Filter>\r
                        </Filter>\r
index 5c5f373..a6dc24f 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file MetadataFilter.h
+ * @file saml/saml2/metadata/MetadataFilter.h
  * 
  * Processes metadata after it's been unmarshalled.
  */
@@ -39,7 +39,8 @@ namespace opensaml {
         class SAML_API MetadataFilter
         {
             MAKE_NONCOPYABLE(MetadataFilter);
-            
+        protected:
+            MetadataFilter() {}
         public:
             virtual ~MetadataFilter() {}
             
@@ -55,11 +56,22 @@ namespace opensaml {
              * signal the removal of information, only for systemic processing failure.
              * 
              * @param xmlObject the metadata to be filtered.
-             * @throws FilterException thrown if an error occurs during the filtering process
              */
             virtual void doFilter(xmltooling::XMLObject& xmlObject) const=0;
         };
 
+        /**
+         * Registers MetadataFilter classes into the runtime.
+         */
+        void SAML_API registerMetadataFilters();
+        
+        /** MetadataFilter that deletes blacklisted entities. */
+        #define BLACKLIST_METADATA_FILTER  "org.opensaml.saml2.metadata.provider.BlacklistMetadataFilter"
+
+        /** MetadataFilter that deletes all but whitelisted entities. */
+        #define WHITELIST_METADATA_FILTER  "org.opensaml.saml2.metadata.provider.WhitelistMetadataFilter"
+        
+        DECL_XMLTOOLING_EXCEPTION(MetadataFilterException,SAML_EXCEPTIONAPI(SAML_API),opensaml::saml2md,xmltooling::XMLToolingException,Exceptions related to metadata filtering);
     };
 };
 
index 3f5f814..4e24bd7 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 /**
- * @file MetadataProvider.h
+ * @file saml/saml2/metadata/MetadataProvider.h
  * 
  * Supplies an individual source of metadata.
  */
@@ -39,41 +39,65 @@ namespace opensaml {
         class SAML_API MetadataProvider : public virtual xmltooling::Lockable
         {
             MAKE_NONCOPYABLE(MetadataProvider);
+            
         protected:
-            MetadataProvider() : m_filter(NULL) {}
+            /**
+             * Constructor. If a DOM is supplied, a set of default logic will be
+             * used to identify and build MetadataFilter plugins and install them
+             * into the provider. The following XML content is supported:
+             * 
+             * <ul>
+             *  <li>&lt;MetadataFilter&gt; elements with a type attribute
+             *  <li>&lt;Exclude&gt; elements representing a BlacklistMetadataFilter
+             *  <li>&lt;BlacklistMetadataFilter&gt; element containing &lt;Exclude&gt; elements 
+             *  <li>&lt;Include&gt; elements representing a WhitelistMetadataFilter
+             *  <li>&lt;WhitelistMetadataFilter&gt; element containing &lt;Include&gt; elements 
+             * </ul>
+             * 
+             * XML namespaces are ignored in the processing of these elements.
+             * 
+             * @param e DOM to supply configuration for provider
+             */
+            MetadataProvider(const DOMElement* e=NULL);
             
         public:
-            virtual ~MetadataProvider() {
-                delete m_filter;
-            }
+            /**
+             * Destructor will delete any installed filters.
+             */
+            virtual ~MetadataProvider();
             
             /**
-             * Gets the metadata filter applied to the resolved metadata.
+             * Adds a metadata filter to apply to any resolved metadata. Will not be applied
+             * to metadata that is already loaded.
              * 
-             * @return the metadata filter applied to the resolved metadata
+             * @param newFilter metadata filter to add
              */
-            const MetadataFilter* getMetadataFilter() const {
-                return m_filter;
+            virtual void addMetadataFilter(MetadataFilter* newFilter) {
+                m_filters.push_back(newFilter);
             }
-        
+
             /**
-             * Sets the metadata filter applied to the resolved metadata.
+             * Removes a metadata filter. The caller must delete the filter if necessary.
              * 
-             * @param newFilter the metadata filter applied to the resolved metadata
+             * @param oldFilter metadata filter to remove
+             * @return  the old filter
              */
-            void setMetadataFilter(MetadataFilter* newFilter) {
-                delete m_filter;
-                m_filter=newFilter;
+            virtual MetadataFilter* removeMetadataFilter(MetadataFilter* oldFilter) {
+                for (std::vector<MetadataFilter*>::iterator i=m_filters.begin(); i!=m_filters.end(); i++) {
+                    if (oldFilter==(*i)) {
+                        m_filters.erase(i);
+                        return oldFilter;
+                    }
+                }
+                return NULL;
             }
             
             /**
-             * Should be called after instantiating provider and setting filter, but before
+             * Should be called after instantiating provider and adding filters, but before
              * performing any lookup operations. Allows the provider to defer initialization
              * processes that are likely to result in exceptions until after the provider is
              * safely created. Providers SHOULD perform as much processing as possible in
              * this method so as to report/log any errors that would affect later processing.
-             * Also, any inputs supplied to the factory MUST persist until the completion of
-             * this method, but the caller is then free to modify or delete them.
              */
             virtual void init()=0;
             
@@ -134,7 +158,15 @@ namespace opensaml {
             virtual const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const=0;
 
         protected:
-            MetadataFilter* m_filter;
+            /**
+             * Applies any installed filters to a metadata instance.
+             * 
+             * @param xmlObject the metadata to be filtered
+             */
+            void doFilters(xmltooling::XMLObject& xmlObject) const;
+        
+        private:
+            std::vector<MetadataFilter*> m_filters;
         };
         
         /**
diff --git a/saml/saml2/metadata/impl/BlacklistMetadataFilter.cpp b/saml/saml2/metadata/impl/BlacklistMetadataFilter.cpp
new file mode 100644 (file)
index 0000000..a0acf60
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  Copyright 2001-2006 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.
+ */
+
+/**
+ * BlacklistMetadataFilter.cpp
+ * 
+ * Removes blacklisted entities from a metadata instance
+ */
+
+#include "internal.h"
+#include "saml2/metadata/MetadataFilter.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml2md;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2md {
+                
+        class SAML_DLLLOCAL BlacklistMetadataFilter : public MetadataFilter
+        {
+        public:
+            BlacklistMetadataFilter(const DOMElement* e);
+            ~BlacklistMetadataFilter() {}
+            
+            const char* getId() const { return BLACKLIST_METADATA_FILTER; }
+            void doFilter(XMLObject& xmlObject) const;
+
+        private:
+            void doFilter(EntitiesDescriptor& entities) const;
+            
+            bool found(const XMLCh* id) const {
+                if (!id)
+                    return false;
+#ifdef HAVE_GOOD_STL
+                return m_set.count(id)==1;
+#else
+                auto_ptr_char id2(id);
+                return m_set.count(id2.get())==1;
+#endif
+            }
+
+#ifdef HAVE_GOOD_STL
+            set<xstring> m_set;
+#else
+            set<string> m_set;
+#endif
+        }; 
+
+        MetadataFilter* SAML_DLLLOCAL BlacklistMetadataFilterFactory(const DOMElement* const & e)
+        {
+            return new BlacklistMetadataFilter(e);
+        }
+
+    };
+};
+
+static const XMLCh Exclude[] =  UNICODE_LITERAL_7(E,x,c,l,u,d,e);
+
+BlacklistMetadataFilter::BlacklistMetadataFilter(const DOMElement* e)
+{
+    e = XMLHelper::getFirstChildElement(e);
+    while (e) {
+        if (XMLString::equals(e->getLocalName(), Exclude) && e->hasChildNodes()) {
+#ifdef HAVE_GOOD_STL
+            m_set.insert(e->getFirstChild()->getNodeValue());
+#else
+            auto_ptr_char id(e->getFirstChild()->getNodeValue());
+            m_set.insert(id.get());
+#endif
+        }
+        e = XMLHelper::getNextSiblingElement(e);
+    }
+}
+
+void BlacklistMetadataFilter::doFilter(XMLObject& xmlObject) const
+{
+#ifdef _DEBUG
+    NDC ndc("doFilter");
+#endif
+    
+    try {
+        doFilter(dynamic_cast<EntitiesDescriptor&>(xmlObject));
+        return;
+    }
+    catch (bad_cast) {
+    }
+
+    try {
+        EntityDescriptor& entity = dynamic_cast<EntityDescriptor&>(xmlObject);
+        if (found(entity.getEntityID()))
+            throw MetadataFilterException("BlacklistMetadataFilter instructed to filter the root/only entity in the metadata.");
+        return;
+    }
+    catch (bad_cast) {
+    }
+     
+    throw MetadataFilterException("BlacklistMetadataFilter was given an improper metadata instance to filter.");
+}
+
+void BlacklistMetadataFilter::doFilter(EntitiesDescriptor& entities) const
+{
+    Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
+    
+    VectorOf(EntityDescriptor) v=entities.getEntityDescriptors();
+    for (VectorOf(EntityDescriptor)::size_type i=0; i<v.size(); ) {
+        const XMLCh* id=v[i]->getEntityID();
+        if (found(id)) {
+            auto_ptr_char id2(id);
+            log.info("filtering out blacklisted entity (%s)", id2.get());
+            v.erase(v.begin() + i);
+        }
+        else {
+            i++;
+        }
+    }
+    
+    const vector<EntitiesDescriptor*>& groups=const_cast<const EntitiesDescriptor&>(entities).getEntitiesDescriptors();
+    for (vector<EntitiesDescriptor*>::const_iterator j=groups.begin(); j!=groups.end(); j++)
+        doFilter(*(*j));
+}
index 3026a32..113e1a3 100644 (file)
@@ -101,7 +101,7 @@ static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e);
 static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
 
 FilesystemMetadataProvider::FilesystemMetadataProvider(const DOMElement* e)
-    : m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL)
+    : MetadataProvider(e), m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL)
 {
 #ifdef _DEBUG
     NDC ndc("FilesystemMetadataProvider");
@@ -199,10 +199,7 @@ XMLObject* FilesystemMetadataProvider::load() const
         
         auto_ptr<XMLObject> xmlObjectPtr(xmlObject);
         
-        if (m_filter) {
-            log.info("applying metadata filter (%s)", m_filter->getId());
-            m_filter->doFilter(*xmlObject);
-        }
+        doFilters(*xmlObject);
         
         xmlObjectPtr->releaseThisAndChildrenDOM();
         xmlObjectPtr->setDocument(NULL);
index 191a061..ad9818b 100644 (file)
 #include "internal.h"
 #include "saml2/metadata/MetadataProvider.h"
 
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml2md;
 using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+static const XMLCh Blacklist[] =                    UNICODE_LITERAL_23(B,l,a,c,k,l,i,s,t,M,e,t,a,d,a,t,a,F,i,l,t,e,r);
+static const XMLCh Exclude[] =                      UNICODE_LITERAL_7(E,x,c,l,u,d,e);
+static const XMLCh Include[] =                      UNICODE_LITERAL_7(I,n,c,l,u,d,e);
+static const XMLCh GenericMetadataFilter[] =        UNICODE_LITERAL_14(M,e,t,a,d,a,t,a,F,i,l,t,e,r);
+static const XMLCh type[] =                         UNICODE_LITERAL_4(t,y,p,e);
+static const XMLCh Whitelist[] =                    UNICODE_LITERAL_23(W,h,i,t,e,l,i,s,t,M,e,t,a,d,a,t,a,F,i,l,t,e,r);
+
+MetadataProvider::MetadataProvider(const DOMElement* e)
+{
+#ifdef _DEBUG
+    NDC ndc("MetadataProvider");
+#endif
+    Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
+    SAMLConfig& conf=SAMLConfig::getConfig();
+    
+    // Locate any default recognized filters.
+    try {
+        DOMElement* child = e ? XMLHelper::getFirstChildElement(e) : NULL;
+        while (child) {
+            if (XMLString::equals(child->getLocalName(),GenericMetadataFilter)) {
+                auto_ptr_char t(child->getAttributeNS(NULL,type));
+                if (t.get())
+                    m_filters.push_back(conf.MetadataFilterManager.newPlugin(t.get(),child));
+            }
+            else if (XMLString::equals(child->getLocalName(),Whitelist)) {
+                m_filters.push_back(conf.MetadataFilterManager.newPlugin(WHITELIST_METADATA_FILTER,child));
+            }
+            else if (XMLString::equals(child->getLocalName(),Blacklist)) {
+                m_filters.push_back(conf.MetadataFilterManager.newPlugin(BLACKLIST_METADATA_FILTER,child));
+            }
+            else if (XMLString::equals(child->getLocalName(),Include)) {
+                m_filters.push_back(conf.MetadataFilterManager.newPlugin(WHITELIST_METADATA_FILTER,e));
+            }
+            else if (XMLString::equals(child->getLocalName(),Exclude)) {
+                m_filters.push_back(conf.MetadataFilterManager.newPlugin(BLACKLIST_METADATA_FILTER,e));
+            }
+            child = XMLHelper::getNextSiblingElement(child);
+        }
+    }
+    catch (XMLToolingException&) {
+        for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup<MetadataFilter>());
+        throw;
+    }
+}
+
+MetadataProvider::~MetadataProvider()
+{
+    for_each(m_filters.begin(),m_filters.end(),xmltooling::cleanup<MetadataFilter>());
+}
+
+void MetadataProvider::doFilters(XMLObject& xmlObject) const
+{
+#ifdef _DEBUG
+    NDC ndc("doFilters");
+#endif
+    Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
+    for (std::vector<MetadataFilter*>::const_iterator i=m_filters.begin(); i!=m_filters.end(); i++) {
+        log.info("applying metadata filter (%s)", (*i)->getId());
+        (*i)->doFilter(xmlObject);
+    }
+}
 
 namespace opensaml {
     namespace saml2md {
         SAML_DLLLOCAL PluginManager<MetadataProvider,const DOMElement*>::Factory FilesystemMetadataProviderFactory; 
+        SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory BlacklistMetadataFilterFactory; 
+        SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory WhitelistMetadataFilterFactory; 
     };
 };
 
@@ -35,3 +105,9 @@ void SAML_API opensaml::saml2md::registerMetadataProviders()
 {
     SAMLConfig::getConfig().MetadataProviderManager.registerFactory(FILESYSTEM_METADATA_PROVIDER, FilesystemMetadataProviderFactory);
 }
+
+void SAML_API opensaml::saml2md::registerMetadataFilters()
+{
+    SAMLConfig::getConfig().MetadataFilterManager.registerFactory(BLACKLIST_METADATA_FILTER, BlacklistMetadataFilterFactory);
+    SAMLConfig::getConfig().MetadataFilterManager.registerFactory(WHITELIST_METADATA_FILTER, WhitelistMetadataFilterFactory);
+}
diff --git a/saml/saml2/metadata/impl/WhitelistMetadataFilter.cpp b/saml/saml2/metadata/impl/WhitelistMetadataFilter.cpp
new file mode 100644 (file)
index 0000000..47b39b2
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  Copyright 2001-2006 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.
+ */
+
+/**
+ * WhitelistMetadataFilter.cpp
+ * 
+ * Removes non-whitelisted entities from a metadata instance
+ */
+
+#include "internal.h"
+#include "saml2/metadata/MetadataFilter.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace opensaml::saml2md;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2md {
+                
+        class SAML_DLLLOCAL WhitelistMetadataFilter : public MetadataFilter
+        {
+        public:
+            WhitelistMetadataFilter(const DOMElement* e);
+            ~WhitelistMetadataFilter() {}
+            
+            const char* getId() const { return WHITELIST_METADATA_FILTER; }
+            void doFilter(XMLObject& xmlObject) const;
+
+        private:
+            void doFilter(EntitiesDescriptor& entities) const;
+            
+            bool found(const XMLCh* id) const {
+                if (!id)
+                    return false;
+#ifdef HAVE_GOOD_STL
+                return m_set.count(id)==1;
+#else
+                auto_ptr_char id2(id);
+                return m_set.count(id2.get())==1;
+#endif
+            }
+
+#ifdef HAVE_GOOD_STL
+            set<xstring> m_set;
+#else
+            set<string> m_set;
+#endif
+        }; 
+
+        MetadataFilter* SAML_DLLLOCAL WhitelistMetadataFilterFactory(const DOMElement* const & e)
+        {
+            return new WhitelistMetadataFilter(e);
+        }
+
+    };
+};
+
+static const XMLCh Include[] =  UNICODE_LITERAL_7(I,n,c,l,u,d,e);
+
+WhitelistMetadataFilter::WhitelistMetadataFilter(const DOMElement* e)
+{
+    e = XMLHelper::getFirstChildElement(e);
+    while (e) {
+        if (XMLString::equals(e->getLocalName(), Include) && e->hasChildNodes()) {
+#ifdef HAVE_GOOD_STL
+            m_set.insert(e->getFirstChild()->getNodeValue());
+#else
+            auto_ptr_char id(e->getFirstChild()->getNodeValue());
+            m_set.insert(id.get());
+#endif
+        }
+        e = XMLHelper::getNextSiblingElement(e);
+    }
+}
+
+void WhitelistMetadataFilter::doFilter(XMLObject& xmlObject) const
+{
+#ifdef _DEBUG
+    NDC ndc("doFilter");
+#endif
+    
+    try {
+        doFilter(dynamic_cast<EntitiesDescriptor&>(xmlObject));
+        return;
+    }
+    catch (bad_cast) {
+    }
+
+    try {
+        EntityDescriptor& entity = dynamic_cast<EntityDescriptor&>(xmlObject);
+        if (!found(entity.getEntityID()))
+            throw MetadataFilterException("WhitelistMetadataFilter instructed to filter the root/only entity in the metadata.");
+        return;
+    }
+    catch (bad_cast) {
+    }
+     
+    throw MetadataFilterException("WhitelistMetadataFilter was given an improper metadata instance to filter.");
+}
+
+void WhitelistMetadataFilter::doFilter(EntitiesDescriptor& entities) const
+{
+    Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
+    
+    VectorOf(EntityDescriptor) v=entities.getEntityDescriptors();
+    for (VectorOf(EntityDescriptor)::size_type i=0; i<v.size(); ) {
+        const XMLCh* id=v[i]->getEntityID();
+        if (!found(id)) {
+            auto_ptr_char id2(id);
+            log.info("filtering out non-whitelisted entity (%s)", id2.get());
+            v.erase(v.begin() + i);
+        }
+        else {
+            i++;
+        }
+    }
+
+    const vector<EntitiesDescriptor*>& groups=const_cast<const EntitiesDescriptor&>(entities).getEntitiesDescriptors();
+    for (vector<EntitiesDescriptor*>::const_iterator j=groups.begin(); j!=groups.end(); j++)
+        doFilter(*(*j));
+}
index b959c5a..be61ae8 100644 (file)
@@ -53,7 +53,8 @@ samltest_h = \
     saml2/core/impl/StatusDetail20Test.h \
     saml2/core/impl/StatusMessage20Test.h \
     saml2/core/impl/StatusResponse20Test.h\
-    saml2/core/impl/Terminate20Test.h
+    saml2/core/impl/Terminate20Test.h \
+    saml2/metadata/FilesystemMetadataProviderTest.h
 
 noinst_HEADERS = \
     internal.h \
diff --git a/samltest/data/saml2/metadata/FilesystemMetadataProvider.xml b/samltest/data/saml2/metadata/FilesystemMetadataProvider.xml
new file mode 100644 (file)
index 0000000..05ef707
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FilesystemMetadataProvider path="../samltest/data/saml2/metadata/InCommon-metadata.xml" validate="0"/>
diff --git a/samltest/data/saml2/metadata/FilesystemWithBlacklists.xml b/samltest/data/saml2/metadata/FilesystemWithBlacklists.xml
new file mode 100644 (file)
index 0000000..bdba203
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FilesystemMetadataProvider path="../samltest/data/saml2/metadata/InCommon-metadata.xml" validate="0">
+    <BlacklistMetadataFilter>
+        <Exclude>urn:mace:incommon:washington.edu</Exclude>
+        <Exclude>urn:mace:incommon:osu.edu</Exclude>
+    </BlacklistMetadataFilter>
+    <MetadataFilter type="org.opensaml.saml2.metadata.provider.BlacklistMetadataFilter">
+        <Exclude>urn:mace:incommon:internet2.edu</Exclude>
+    </MetadataFilter>
+</FilesystemMetadataProvider>
diff --git a/samltest/data/saml2/metadata/FilesystemWithWhitelists.xml b/samltest/data/saml2/metadata/FilesystemWithWhitelists.xml
new file mode 100644 (file)
index 0000000..f9f3636
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<FilesystemMetadataProvider path="../samltest/data/saml2/metadata/InCommon-metadata.xml" validate="0">
+    <WhitelistMetadataFilter>
+        <Include>urn:mace:incommon:washington.edu</Include>
+        <Include>urn:mace:incommon:osu.edu</Include>
+    </WhitelistMetadataFilter>
+</FilesystemMetadataProvider>
index 049ab31..a6da0a7 100644 (file)
@@ -21,42 +21,45 @@ using namespace opensaml::saml2md;
 \r
 class FilesystemMetadataProviderTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase {\r
     XMLCh* entityID;\r
+    XMLCh* entityID2;\r
     XMLCh* supportedProtocol;\r
     XMLCh* supportedProtocol2;\r
-    MetadataProvider* metadataProvider;\r
 \r
 public:\r
     void setUp() {\r
         entityID=XMLString::transcode("urn:mace:incommon:washington.edu");\r
+        entityID2=XMLString::transcode("urn:mace:incommon:rochester.edu");\r
         supportedProtocol=XMLString::transcode("urn:oasis:names:tc:SAML:1.1:protocol");\r
         supportedProtocol2=XMLString::transcode("urn:mace:shibboleth:1.0");\r
-        \r
-        auto_ptr_XMLCh MP("MetadataProvider");\r
-        auto_ptr_XMLCh path("path");\r
-        auto_ptr_XMLCh validate("validate");\r
-        string s=data_path + "saml2/metadata/InCommon-metadata.xml";\r
-        auto_ptr_XMLCh file(s.c_str());\r
-        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().newDocument();\r
-        XercesJanitor<DOMDocument> janitor(doc);\r
-        DOMElement* root=doc->createElementNS(NULL,MP.get());\r
-        root->setAttributeNS(NULL,path.get(),file.get());\r
-        root->setAttributeNS(NULL,validate.get(),XMLConstants::XML_ZERO);\r
-        metadataProvider = NULL;\r
-        metadataProvider = SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,root);\r
-        metadataProvider->init();\r
-        \r
         SAMLObjectBaseTestCase::setUp();\r
     }\r
     \r
     void tearDown() {\r
         XMLString::release(&entityID);\r
+        XMLString::release(&entityID2);\r
         XMLString::release(&supportedProtocol);\r
-        delete metadataProvider;\r
+        XMLString::release(&supportedProtocol2);\r
         SAMLObjectBaseTestCase::tearDown();\r
     }\r
 \r
-    void testEntityDescriptor() {\r
-        Locker locker(metadataProvider);\r
+    void testFilesystemProvider() {\r
+        string config = data_path + "saml2/metadata/FilesystemMetadataProvider.xml";\r
+        ifstream in(config.c_str());\r
+        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+        XercesJanitor<DOMDocument> janitor(doc);\r
+\r
+        auto_ptr_XMLCh path("path");\r
+        string s = data_path + "saml2/metadata/InCommon-metadata.xml";\r
+        auto_ptr_XMLCh file(s.c_str());\r
+        doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());\r
+\r
+        auto_ptr<MetadataProvider> metadataProvider(\r
+            SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
+            );\r
+        metadataProvider->init();\r
+        \r
+\r
+        Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID);\r
         TSM_ASSERT("Retrieved entity descriptor was null", descriptor!=NULL);\r
         assertEquals("Entity's ID does not match requested ID", entityID, descriptor->getEntityID());\r
@@ -65,4 +68,53 @@ public:
         TSM_ASSERT("Role lookup failed", descriptor->getIDPSSODescriptor(supportedProtocol2)!=NULL);\r
     }\r
 \r
+    void testFilesystemWithBlacklists() {\r
+        string config = data_path + "saml2/metadata/FilesystemWithBlacklists.xml";\r
+        ifstream in(config.c_str());\r
+        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+        XercesJanitor<DOMDocument> janitor(doc);\r
+\r
+        auto_ptr_XMLCh path("path");\r
+        string s = data_path + "saml2/metadata/InCommon-metadata.xml";\r
+        auto_ptr_XMLCh file(s.c_str());\r
+        doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());\r
+\r
+        auto_ptr<MetadataProvider> metadataProvider(\r
+            SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
+            );\r
+        metadataProvider->init();\r
+        \r
+\r
+        Locker locker(metadataProvider.get());\r
+        const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID);\r
+        TSM_ASSERT("Retrieved entity descriptor was not null", descriptor==NULL);\r
+        descriptor = metadataProvider->getEntityDescriptor(entityID2);\r
+        TSM_ASSERT("Retrieved entity descriptor was null", descriptor!=NULL);\r
+        assertEquals("Entity's ID does not match requested ID", entityID2, descriptor->getEntityID());\r
+    }\r
+\r
+    void testFilesystemWithWhitelists() {\r
+        string config = data_path + "saml2/metadata/FilesystemWithWhitelists.xml";\r
+        ifstream in(config.c_str());\r
+        DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+        XercesJanitor<DOMDocument> janitor(doc);\r
+\r
+        auto_ptr_XMLCh path("path");\r
+        string s = data_path + "saml2/metadata/InCommon-metadata.xml";\r
+        auto_ptr_XMLCh file(s.c_str());\r
+        doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());\r
+\r
+        auto_ptr<MetadataProvider> metadataProvider(\r
+            SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
+            );\r
+        metadataProvider->init();\r
+        \r
+\r
+        Locker locker(metadataProvider.get());\r
+        const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID2);\r
+        TSM_ASSERT("Retrieved entity descriptor was not null", descriptor==NULL);\r
+        descriptor = metadataProvider->getEntityDescriptor(entityID);\r
+        TSM_ASSERT("Retrieved entity descriptor was null", descriptor!=NULL);\r
+        assertEquals("Entity's ID does not match requested ID", entityID, descriptor->getEntityID());\r
+    }\r
 };\r