Add signature-checking metadata filter.
authorScott Cantor <cantor.2@osu.edu>
Sun, 13 Aug 2006 23:02:54 +0000 (23:02 +0000)
committerScott Cantor <cantor.2@osu.edu>
Sun, 13 Aug 2006 23:02:54 +0000 (23:02 +0000)
saml/Makefile.am
saml/saml.vcproj
saml/saml2/metadata/MetadataFilter.h
saml/saml2/metadata/MetadataProvider.h
saml/saml2/metadata/impl/MetadataProvider.cpp
saml/saml2/metadata/impl/SignatureMetadataFilter.cpp [new file with mode: 0644]
samltest/data/saml2/metadata/FilesystemMetadataProvider.xml
samltest/internal.h
samltest/saml2/metadata/FilesystemMetadataProviderTest.h

index 36e8611..869eb35 100644 (file)
@@ -77,6 +77,7 @@ libsaml_la_SOURCES = \
        saml2/metadata/impl/MetadataProvider.cpp \
        saml2/metadata/impl/MetadataSchemaValidators.cpp \
        saml2/metadata/impl/ObservableMetadataProvider.cpp \
        saml2/metadata/impl/MetadataProvider.cpp \
        saml2/metadata/impl/MetadataSchemaValidators.cpp \
        saml2/metadata/impl/ObservableMetadataProvider.cpp \
+       saml2/metadata/impl/SignatureMetadataFilter.cpp \
        saml2/metadata/impl/WhitelistMetadataFilter.cpp \
        signature/ContentReference.cpp \
        signature/SignatureProfileValidator.cpp \
        saml2/metadata/impl/WhitelistMetadataFilter.cpp \
        signature/ContentReference.cpp \
        signature/SignatureProfileValidator.cpp \
index ce4d609..73c7317 100644 (file)
                                                        >\r
                                                </File>\r
                                                <File\r
                                                        >\r
                                                </File>\r
                                                <File\r
+                                                       RelativePath=".\saml2\metadata\impl\SignatureMetadataFilter.cpp"\r
+                                                       >\r
+                                               </File>\r
+                                               <File\r
                                                        RelativePath=".\saml2\metadata\impl\WhitelistMetadataFilter.cpp"\r
                                                        >\r
                                                </File>\r
                                                        RelativePath=".\saml2\metadata\impl\WhitelistMetadataFilter.cpp"\r
                                                        >\r
                                                </File>\r
index a6dc24f..d383c56 100644 (file)
@@ -70,6 +70,9 @@ namespace opensaml {
 
         /** MetadataFilter that deletes all but whitelisted entities. */
         #define WHITELIST_METADATA_FILTER  "org.opensaml.saml2.metadata.provider.WhitelistMetadataFilter"
 
         /** MetadataFilter that deletes all but whitelisted entities. */
         #define WHITELIST_METADATA_FILTER  "org.opensaml.saml2.metadata.provider.WhitelistMetadataFilter"
+
+        /** MetadataFilter that verifies signatures and filters out any that don't pass. */
+        #define SIGNATURE_METADATA_FILTER  "org.opensaml.saml2.metadata.provider.SignatureMetadataFilter"
         
         DECL_XMLTOOLING_EXCEPTION(MetadataFilterException,SAML_EXCEPTIONAPI(SAML_API),opensaml::saml2md,xmltooling::XMLToolingException,Exceptions related to metadata filtering);
     };
         
         DECL_XMLTOOLING_EXCEPTION(MetadataFilterException,SAML_EXCEPTIONAPI(SAML_API),opensaml::saml2md,xmltooling::XMLToolingException,Exceptions related to metadata filtering);
     };
index f773e41..583c1b2 100644 (file)
@@ -57,10 +57,11 @@ namespace opensaml {
              * 
              * <ul>
              *  <li>&lt;KeyResolver&gt; elements with a type attribute
              * 
              * <ul>
              *  <li>&lt;KeyResolver&gt; elements with a type attribute
-             *  <li>&lt;MetadataFilter&gt; elements with a type attribute
+             *  <li>&lt;MetadataFilter&gt; elements with a type attribute and type-specific content
              *  <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;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;SignatureMetadataFilter&gt; element containing a &lt;KeyResolver&gt; element 
              *  <li>&lt;WhitelistMetadataFilter&gt; element containing &lt;Include&gt; elements 
              * </ul>
              * 
              *  <li>&lt;WhitelistMetadataFilter&gt; element containing &lt;Include&gt; elements 
              * </ul>
              * 
index 3e88ff3..151d6a8 100644 (file)
@@ -38,6 +38,7 @@ namespace opensaml {
         SAML_DLLLOCAL PluginManager<MetadataProvider,const DOMElement*>::Factory FilesystemMetadataProviderFactory; 
         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory BlacklistMetadataFilterFactory; 
         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory WhitelistMetadataFilterFactory; 
         SAML_DLLLOCAL PluginManager<MetadataProvider,const DOMElement*>::Factory FilesystemMetadataProviderFactory; 
         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory BlacklistMetadataFilterFactory; 
         SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory WhitelistMetadataFilterFactory; 
+        SAML_DLLLOCAL PluginManager<MetadataFilter,const DOMElement*>::Factory SignatureMetadataFilterFactory; 
     };
 };
 
     };
 };
 
@@ -53,10 +54,12 @@ void SAML_API opensaml::saml2md::registerMetadataFilters()
 {
     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(BLACKLIST_METADATA_FILTER, BlacklistMetadataFilterFactory);
     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(WHITELIST_METADATA_FILTER, WhitelistMetadataFilterFactory);
 {
     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(BLACKLIST_METADATA_FILTER, BlacklistMetadataFilterFactory);
     SAMLConfig::getConfig().MetadataFilterManager.registerFactory(WHITELIST_METADATA_FILTER, WhitelistMetadataFilterFactory);
+    SAMLConfig::getConfig().MetadataFilterManager.registerFactory(SIGNATURE_METADATA_FILTER, SignatureMetadataFilterFactory);
 }
 
 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 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);
 }
 
 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 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);
+static const XMLCh SigFilter[] =                    UNICODE_LITERAL_23(S,i,g,n,a,t,u,r,e,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 GenericKeyResolver[] =           UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,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 GenericKeyResolver[] =           UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r);
@@ -78,11 +81,18 @@ MetadataProvider::MetadataProvider(const DOMElement* e) : m_resolver(NULL)
                 auto_ptr_char t(child->getAttributeNS(NULL,type));
                 if (t.get())
                     m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child);
                 auto_ptr_char t(child->getAttributeNS(NULL,type));
                 if (t.get())
                     m_resolver = XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),child);
+                else
+                    throw UnknownExtensionException("<KeyResolver> element found with no type attribute");
             }
             else 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(),GenericMetadataFilter)) {
                 auto_ptr_char t(child->getAttributeNS(NULL,type));
                 if (t.get())
                     m_filters.push_back(conf.MetadataFilterManager.newPlugin(t.get(),child));
+                else
+                    throw UnknownExtensionException("<MetadataFilter> element found with no type attribute");
+            }
+            else if (XMLString::equals(child->getLocalName(),SigFilter)) {
+                m_filters.push_back(conf.MetadataFilterManager.newPlugin(SIGNATURE_METADATA_FILTER,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(),Whitelist)) {
                 m_filters.push_back(conf.MetadataFilterManager.newPlugin(WHITELIST_METADATA_FILTER,child));
diff --git a/saml/saml2/metadata/impl/SignatureMetadataFilter.cpp b/saml/saml2/metadata/impl/SignatureMetadataFilter.cpp
new file mode 100644 (file)
index 0000000..64c43f8
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  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 "signature/SignatureProfileValidator.h"
+
+#include <log4cpp/Category.hh>
+
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/signature/SignatureValidator.h>
+
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2md {
+                
+        class SAML_DLLLOCAL SignatureMetadataFilter : public MetadataFilter
+        {
+        public:
+            SignatureMetadataFilter(const DOMElement* e);
+            ~SignatureMetadataFilter() {
+                delete m_sigValidator;
+            }
+            
+            const char* getId() const { return SIGNATURE_METADATA_FILTER; }
+            void doFilter(XMLObject& xmlObject) const;
+
+        private:
+            void doFilter(EntitiesDescriptor& entities, bool rootObject=false) const;
+            void verifySignature(Signature* sig) const {
+                if (sig) {
+                    m_profileValidator.validate(sig);
+                    m_sigValidator->validate(sig);
+                }
+            }
+            
+            SignatureProfileValidator m_profileValidator;
+            SignatureValidator* m_sigValidator;
+        }; 
+
+        MetadataFilter* SAML_DLLLOCAL SignatureMetadataFilterFactory(const DOMElement* const & e)
+        {
+            return new SignatureMetadataFilter(e);
+        }
+
+    };
+};
+
+static const XMLCh GenericKeyResolver[] =   UNICODE_LITERAL_11(K,e,y,R,e,s,o,l,v,e,r);
+static const XMLCh type[] =                 UNICODE_LITERAL_4(t,y,p,e);
+
+SignatureMetadataFilter::SignatureMetadataFilter(const DOMElement* e) : m_sigValidator(NULL)
+{
+    e = XMLHelper::getFirstChildElement(e, GenericKeyResolver);
+    auto_ptr_char t(e ? e->getAttributeNS(NULL,type) : NULL);
+    if (t.get()) {
+        auto_ptr<KeyResolver> kr(XMLToolingConfig::getConfig().KeyResolverManager.newPlugin(t.get(),e));
+        m_sigValidator = new SignatureValidator(kr.get());
+        kr.release();
+    }
+    else
+        throw MetadataFilterException("missing <KeyResolver> element, or no type attribute found");
+}
+
+void SignatureMetadataFilter::doFilter(XMLObject& xmlObject) const
+{
+#ifdef _DEBUG
+    NDC ndc("doFilter");
+#endif
+    
+    try {
+        EntitiesDescriptor& entities = dynamic_cast<EntitiesDescriptor&>(xmlObject);
+        doFilter(entities, true);
+        return;
+    }
+    catch (bad_cast) {
+    }
+
+    try {
+        EntityDescriptor& entity = dynamic_cast<EntityDescriptor&>(xmlObject);
+        if (!entity.getSignature())
+            throw MetadataFilterException("Root metadata element was unsigned.");
+        verifySignature(entity.getSignature());
+    }
+    catch (bad_cast) {
+    }
+     
+    throw MetadataFilterException("SignatureMetadataFilter was given an improper metadata instance to filter.");
+}
+
+void SignatureMetadataFilter::doFilter(EntitiesDescriptor& entities, bool rootObject) const
+{
+    Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
+    
+    Signature* sig = entities.getSignature();
+    if (!sig && rootObject)
+        throw MetadataFilterException("Root metadata element was unsigned.");
+    verifySignature(sig);
+    
+    VectorOf(EntityDescriptor) v=entities.getEntityDescriptors();
+    for (VectorOf(EntityDescriptor)::size_type i=0; i<v.size(); ) {
+        try {
+            verifySignature(v[i]->getSignature());
+            i++;
+        }
+        catch (XMLToolingException& e) {
+            auto_ptr_char id(v[i]->getEntityID());
+            log.info("filtering out entity (%s) after failed signature check: ", id.get(), e.what());
+            v.erase(v.begin() + i);
+        }
+    }
+    
+    VectorOf(EntitiesDescriptor) w=entities.getEntitiesDescriptors();
+    for (VectorOf(EntitiesDescriptor)::size_type j=0; j<w.size(); ) {
+        try {
+            verifySignature(w[j]->getSignature());
+            j++;
+        }
+        catch (XMLToolingException& e) {
+            auto_ptr_char name(w[j]->getName());
+            log.info("filtering out group (%s) after failed signature check: ", name.get(), e.what());
+            w.erase(w.begin() + j);
+        }
+    }
+}
index 05ef707..403ad46 100644 (file)
@@ -1,2 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
-<FilesystemMetadataProvider path="../samltest/data/saml2/metadata/InCommon-metadata.xml" validate="0"/>
+<FilesystemMetadataProvider path="../samltest/data/saml2/metadata/InCommon-metadata.xml" validate="0">
+    <SignatureMetadataFilter>
+        <KeyResolver type="org.opensaml.xmlooling.InlineKeyResolver"/>
+    </SignatureMetadataFilter>
+</FilesystemMetadataProvider>
index 7e82e01..4575bc4 100644 (file)
@@ -72,8 +72,16 @@ protected:
         }
     }
 
         }
     }
 
-    void assertEquals(const char* failMessage, DOMDocument* expectedDOM, XMLObject* xmlObject) {
-        DOMElement* generatedDOM = xmlObject->marshall();
+    void assertEquals(const char* failMessage, DOMDocument* expectedDOM, XMLObject* xmlObject, bool canMarshall=true) {
+        DOMElement* generatedDOM = xmlObject->getDOM();
+        if (!generatedDOM) {
+            if (!canMarshall) {
+                TSM_ASSERT("DOM not available", false);
+            }
+            else {
+                generatedDOM = xmlObject->marshall();
+            }
+        }
         if (!generatedDOM->isEqualNode(expectedDOM->getDocumentElement())) {
             string buf;
             XMLHelper::serialize(generatedDOM, buf);
         if (!generatedDOM->isEqualNode(expectedDOM->getDocumentElement())) {
             string buf;
             XMLHelper::serialize(generatedDOM, buf);
@@ -85,8 +93,8 @@ protected:
         }
     }
 
         }
     }
 
-    void assertEquals(DOMDocument* expectedDOM, XMLObject* xmlObject) {
-        assertEquals("Marshalled DOM was not the same as the expected DOM", expectedDOM, xmlObject);
+    void assertEquals(DOMDocument* expectedDOM, XMLObject* xmlObject, bool canMarshall=true) {
+        assertEquals("Marshalled DOM was not the same as the expected DOM", expectedDOM, xmlObject, canMarshall);
         delete xmlObject;
     }
 
         delete xmlObject;
     }
 
index a9c1f83..73b18b0 100644 (file)
@@ -58,9 +58,14 @@ public:
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
-        metadataProvider->init();\r
+        try {\r
+            metadataProvider->init();\r
+        }\r
+        catch (XMLToolingException& ex) {\r
+            TS_TRACE(ex.what());\r
+            throw;\r
+        }\r
         \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
         Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID);\r
         TSM_ASSERT("Retrieved entity descriptor was null", descriptor!=NULL);\r
@@ -91,8 +96,13 @@ public:
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
-        metadataProvider->init();\r
-        \r
+        try {\r
+            metadataProvider->init();\r
+        }\r
+        catch (XMLToolingException& ex) {\r
+            TS_TRACE(ex.what());\r
+            throw;\r
+        }\r
 \r
         Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID);\r
 \r
         Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID);\r
@@ -116,8 +126,13 @@ public:
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
         auto_ptr<MetadataProvider> metadataProvider(\r
             SAMLConfig::getConfig().MetadataProviderManager.newPlugin(FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement())\r
             );\r
-        metadataProvider->init();\r
-        \r
+        try {\r
+            metadataProvider->init();\r
+        }\r
+        catch (XMLToolingException& ex) {\r
+            TS_TRACE(ex.what());\r
+            throw;\r
+        }\r
 \r
         Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID2);\r
 \r
         Locker locker(metadataProvider.get());\r
         const EntityDescriptor* descriptor = metadataProvider->getEntityDescriptor(entityID2);\r