https://issues.shibboleth.net/jira/browse/CPPOST-69
authorScott Cantor <cantor.2@osu.edu>
Wed, 28 Sep 2011 02:48:19 +0000 (02:48 +0000)
committerScott Cantor <cantor.2@osu.edu>
Wed, 28 Sep 2011 02:48:19 +0000 (02:48 +0000)
configure.ac
saml/Makefile.am
saml/saml2/metadata/MetadataProvider.h
saml/saml2/metadata/impl/FolderMetadataProvider.cpp [new file with mode: 0644]
saml/saml2/metadata/impl/MetadataProvider.cpp

index 76e8787..7632a13 100644 (file)
@@ -63,6 +63,7 @@ fi
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
 AC_TYPE_SIZE_T
+AC_HEADER_DIRENT
 
 # Checks for library functions.
 AC_CHECK_FUNCS([strchr strdup strstr])
index 9a690bd..1dab792 100644 (file)
@@ -147,6 +147,7 @@ libsaml_la_SOURCES = \
        saml2/metadata/impl/DiscoverableMetadataProvider.cpp \
        saml2/metadata/impl/DynamicMetadataProvider.cpp \
        saml2/metadata/impl/EntityRoleMetadataFilter.cpp \
+       saml2/metadata/impl/FolderMetadataProvider.cpp \
        saml2/metadata/impl/MetadataCredentialContext.cpp \
        saml2/metadata/impl/MetadataCredentialCriteria.cpp \
        saml2/metadata/impl/MetadataImpl.cpp \
index 571d4bd..dad99c5 100644 (file)
@@ -271,6 +271,9 @@ namespace opensaml {
         /** MetadataProvider that wraps a sequence of metadata providers. */
         #define CHAINING_METADATA_PROVIDER  "Chaining"
 
+        /** MetadataProvider that loads a directory of files. */
+        #define FOLDER_METADATA_PROVIDER  "Folder"
+
         /** MetadataProvider that returns an empty "dummy" entity descriptor. */
         #define NULL_METADATA_PROVIDER  "Null"
 
diff --git a/saml/saml2/metadata/impl/FolderMetadataProvider.cpp b/saml/saml2/metadata/impl/FolderMetadataProvider.cpp
new file mode 100644 (file)
index 0000000..5f89856
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * Licensed to the University Corporation for Advanced Internet
+ * Development, Inc. (UCAID) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * UCAID licenses this file to you 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.
+ */
+
+/**
+ * FolderMetadataProvider.cpp
+ * 
+ * MetadataProvider that loads all files in a directory.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+
+#include <memory>
+#include <xercesc/util/XMLUniDefs.hpp>
+#include <xmltooling/logging.h>
+#include <xmltooling/XMLToolingConfig.h>
+#include <xmltooling/util/PathResolver.h>
+#include <xmltooling/util/XMLHelper.h>
+
+#ifndef WIN32
+# ifdef HAVE_SYS_TYPES_H && HAVE_DIRENT_H
+#  include <sys/types.h>
+#  include <dirent.h>
+# else
+#  #error Unsupported directory library headers.
+# endif
+#endif
+
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling::logging;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+    namespace saml2md {
+
+        static const XMLCh Chaining[] =             UNICODE_LITERAL_8(C,h,a,i,n,i,n,g);
+        static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);
+        static const XMLCh discoveryFeed[] =        UNICODE_LITERAL_13(d,i,s,c,o,v,e,r,y,F,e,e,d);
+        static const XMLCh legacyOrgNames[] =       UNICODE_LITERAL_14(l,e,g,a,c,y,O,r,g,N,a,m,e,s);
+        static const XMLCh path[] =                 UNICODE_LITERAL_4(p,a,t,h);
+        static const XMLCh precedence[] =           UNICODE_LITERAL_10(p,r,e,c,e,d,e,n,c,e);
+        static const XMLCh reloadChanges[] =        UNICODE_LITERAL_13(r,e,l,o,a,d,C,h,a,n,g,e,s);
+        static const XMLCh validate[] =             UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
+        static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);
+        static const XMLCh _XML[] =                 UNICODE_LITERAL_3(X,M,L);
+    
+        MetadataProvider* SAML_DLLLOCAL FolderMetadataProviderFactory(const DOMElement* const & e)
+        {
+            // The goal here is to construct a configuration for a chain of file-based providers
+            // based on the content of the directory we're given.
+
+            auto_ptr_char p(e->getAttributeNS(nullptr, path));
+            if (!p.get() || !*p.get()) {
+                throw MetadataException("Folder MetadataProvider missing path setting.");
+            }
+
+            string fullname, loc(p.get());
+            XMLToolingConfig::getConfig().getPathResolver()->resolve(loc, PathResolver::XMLTOOLING_CFG_FILE);
+
+            // First we build a new root element of the right type, and copy in the precedence setting.
+            DOMElement* root = e->getOwnerDocument()->createElementNS(nullptr, _MetadataProvider);
+            root->setAttributeNS(nullptr, _type, Chaining);
+            if (e->hasAttributeNS(nullptr, precedence))
+                root->setAttributeNS(nullptr, precedence, e->getAttributeNS(nullptr, precedence));
+
+            Category& log = Category::getInstance(SAML_LOGCAT".Metadata.Folder");
+            log.info("loading metadata files from folder (%s)", loc.c_str());
+
+#ifdef WIN32
+            WIN32_FIND_DATA f;
+            fullname = loc + "/*";
+            HANDLE h = FindFirstFile(fullname.c_str(), &f);
+            if (h == INVALID_HANDLE_VALUE) {
+                if (GetLastError() != ERROR_FILE_NOT_FOUND)
+                    throw MetadataException("Folder MetadataProvider unable to open directory ($1)", params(1, loc.c_str()));
+                log.warn("no files found in folder (%s)", loc.c_str());
+                return SAMLConfig::getConfig().MetadataProviderManager.newPlugin(CHAINING_METADATA_PROVIDER, root);
+            }
+            do {
+                if (f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+                    log.warn("nested folders not supported, skipping (%s)", f.cFileName);
+                    continue;
+                }
+                fullname = loc + '/' + f.cFileName;
+                log.info("will create metadata source from (%s)", fullname.c_str());
+                auto_ptr_XMLCh entry(fullname.c_str());
+#else
+            DIR* d = opendir(loc.c_str());
+            if (!d) {
+                throw MetadataException("Folder MetadataProvider unable to open directory ($1)", params(1, loc.c_str()));
+            }
+            struct dirent* ent;
+            while(readdir_r(d, ent, &ent) == 0 && ent) {
+                if (ent->d_type & DT_DIR) {
+                    if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
+                        log.warn("nested folders not supported, skipping (%s)", ent->d_name);
+                    continue;
+                }
+                fullname = loc + '/' + ent->d_name;
+                log.info("will create metadata source from (%s)", fullname.c_str());
+                auto_ptr_XMLCh entry(fullname.c_str());
+#endif
+                DOMElement* child = e->getOwnerDocument()->createElementNS(nullptr, _MetadataProvider);
+                child->setAttributeNS(nullptr, _type, _XML);
+                child->setAttributeNS(nullptr, path, entry.get());
+                if (e->hasAttributeNS(nullptr, validate))
+                    child->setAttributeNS(nullptr, validate, e->getAttributeNS(nullptr, validate));
+                if (e->hasAttributeNS(nullptr, reloadChanges))
+                    child->setAttributeNS(nullptr, reloadChanges, e->getAttributeNS(nullptr, reloadChanges));
+                if (e->hasAttributeNS(nullptr, discoveryFeed))
+                    child->setAttributeNS(nullptr, discoveryFeed, e->getAttributeNS(nullptr, discoveryFeed));
+                if (e->hasAttributeNS(nullptr, legacyOrgNames))
+                    child->setAttributeNS(nullptr, legacyOrgNames, e->getAttributeNS(nullptr, legacyOrgNames));
+
+                DOMElement* filter = XMLHelper::getFirstChildElement(e);
+                while (filter) {
+                    child->appendChild(filter->cloneNode(true));
+                    filter = XMLHelper::getNextSiblingElement(filter);
+                }
+                root->appendChild(child);
+
+#ifdef WIN32
+            } while (FindNextFile(h, &f));
+            FindClose(h);
+#else
+            }
+            closedir(d);
+#endif
+            return SAMLConfig::getConfig().MetadataProviderManager.newPlugin(CHAINING_METADATA_PROVIDER, root);
+        }
+
+    };
+};
index de18ceb..719f8cd 100644 (file)
@@ -46,6 +46,7 @@ namespace opensaml {
         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<MetadataProvider,string,const DOMElement*>::Factory FolderMetadataProviderFactory;
         SAML_DLLLOCAL PluginManager<MetadataProvider,string,const DOMElement*>::Factory NullMetadataProviderFactory;
         SAML_DLLLOCAL PluginManager<MetadataFilter,string,const DOMElement*>::Factory BlacklistMetadataFilterFactory;
         SAML_DLLLOCAL PluginManager<MetadataFilter,string,const DOMElement*>::Factory WhitelistMetadataFilterFactory;
@@ -61,6 +62,7 @@ void SAML_API opensaml::saml2md::registerMetadataProviders()
     conf.MetadataProviderManager.registerFactory(XML_METADATA_PROVIDER, XMLMetadataProviderFactory);
     conf.MetadataProviderManager.registerFactory(DYNAMIC_METADATA_PROVIDER, DynamicMetadataProviderFactory);
     conf.MetadataProviderManager.registerFactory(CHAINING_METADATA_PROVIDER, ChainingMetadataProviderFactory);
+    conf.MetadataProviderManager.registerFactory(FOLDER_METADATA_PROVIDER, FolderMetadataProviderFactory);
     conf.MetadataProviderManager.registerFactory(NULL_METADATA_PROVIDER, NullMetadataProviderFactory);
 }