From f92e8ef00181805957c44a7d9cc7d82491c0b5cf Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Wed, 28 Sep 2011 02:48:19 +0000 Subject: [PATCH] https://issues.shibboleth.net/jira/browse/CPPOST-69 --- configure.ac | 1 + saml/Makefile.am | 1 + saml/saml2/metadata/MetadataProvider.h | 3 + .../saml2/metadata/impl/FolderMetadataProvider.cpp | 155 +++++++++++++++++++++ saml/saml2/metadata/impl/MetadataProvider.cpp | 2 + 5 files changed, 162 insertions(+) create mode 100644 saml/saml2/metadata/impl/FolderMetadataProvider.cpp diff --git a/configure.ac b/configure.ac index 76e8787..7632a13 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/saml/Makefile.am b/saml/Makefile.am index 9a690bd..1dab792 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -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 \ diff --git a/saml/saml2/metadata/MetadataProvider.h b/saml/saml2/metadata/MetadataProvider.h index 571d4bd..dad99c5 100644 --- a/saml/saml2/metadata/MetadataProvider.h +++ b/saml/saml2/metadata/MetadataProvider.h @@ -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 index 0000000..5f89856 --- /dev/null +++ b/saml/saml2/metadata/impl/FolderMetadataProvider.cpp @@ -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 +#include +#include +#include +#include +#include + +#ifndef WIN32 +# ifdef HAVE_SYS_TYPES_H && HAVE_DIRENT_H +# include +# include +# 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); + } + + }; +}; diff --git a/saml/saml2/metadata/impl/MetadataProvider.cpp b/saml/saml2/metadata/impl/MetadataProvider.cpp index de18ceb..719f8cd 100644 --- a/saml/saml2/metadata/impl/MetadataProvider.cpp +++ b/saml/saml2/metadata/impl/MetadataProvider.cpp @@ -46,6 +46,7 @@ namespace opensaml { SAML_DLLLOCAL PluginManager::Factory XMLMetadataProviderFactory; SAML_DLLLOCAL PluginManager::Factory DynamicMetadataProviderFactory; SAML_DLLLOCAL PluginManager::Factory ChainingMetadataProviderFactory; + SAML_DLLLOCAL PluginManager::Factory FolderMetadataProviderFactory; SAML_DLLLOCAL PluginManager::Factory NullMetadataProviderFactory; SAML_DLLLOCAL PluginManager::Factory BlacklistMetadataFilterFactory; SAML_DLLLOCAL PluginManager::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); } -- 2.1.4