2 * Copyright 2001-2006 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * FilesystemMetadataProvider.cpp
20 * Supplies metadata from a local file, detecting and reloading changes.
24 #include "saml2/metadata/Metadata.h"
25 #include "saml2/metadata/AbstractMetadataProvider.h"
28 #include <sys/types.h>
30 #include <log4cpp/Category.hh>
31 #include <xercesc/framework/LocalFileInputSource.hpp>
32 #include <xercesc/framework/Wrapper4InputSource.hpp>
33 #include <xercesc/util/XMLUniDefs.hpp>
34 #include <xmltooling/util/NDC.h>
35 #include <xmltooling/util/Threads.h>
36 #include <xmltooling/util/XMLConstants.h>
38 using namespace opensaml::saml2md;
39 using namespace xmltooling;
40 using namespace log4cpp;
47 class SAML_DLLLOCAL FilesystemMetadataProvider : public AbstractMetadataProvider
50 FilesystemMetadataProvider(const DOMElement* e);
51 ~FilesystemMetadataProvider();
61 const XMLObject* getMetadata() const {
66 XMLObject* load() const;
69 const DOMElement* m_root; // survives only until init() method is done
77 MetadataProvider* SAML_DLLLOCAL FilesystemMetadataProviderFactory(const DOMElement* const & e)
79 return new FilesystemMetadataProvider(e);
85 static const XMLCh uri[] = UNICODE_LITERAL_3(u,r,i);
86 static const XMLCh url[] = UNICODE_LITERAL_3(u,r,l);
87 static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);
88 static const XMLCh pathname[] = UNICODE_LITERAL_8(p,a,t,h,n,a,m,e);
89 static const XMLCh file[] = UNICODE_LITERAL_4(f,i,l,e);
90 static const XMLCh filename[] = UNICODE_LITERAL_8(f,i,l,e,n,a,m,e);
91 static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);
93 FilesystemMetadataProvider::FilesystemMetadataProvider(const DOMElement* e)
94 : AbstractMetadataProvider(e), m_root(e), m_filestamp(0), m_validate(false), m_lock(NULL), m_object(NULL)
97 NDC ndc("FilesystemMetadataProvider");
99 Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
101 // Establish source of data...
102 const XMLCh* source=e->getAttributeNS(NULL,uri);
103 if (!source || !*source) {
104 source=e->getAttributeNS(NULL,url);
105 if (!source || !*source) {
106 source=e->getAttributeNS(NULL,path);
107 if (!source || !*source) {
108 source=e->getAttributeNS(NULL,pathname);
109 if (!source || !*source) {
110 source=e->getAttributeNS(NULL,file);
111 if (!source || !*source) {
112 source=e->getAttributeNS(NULL,filename);
119 if (source && *source) {
120 const XMLCh* valflag=e->getAttributeNS(NULL,validate);
121 m_validate=(XMLString::equals(valflag,xmlconstants::XML_TRUE) || XMLString::equals(valflag,xmlconstants::XML_ONE));
123 auto_ptr_char temp(source);
125 log.debug("using external metadata file (%s)", temp.get());
128 struct _stat stat_buf;
129 if (_stat(m_source.c_str(), &stat_buf) == 0)
131 struct stat stat_buf;
132 if (stat(m_source.c_str(), &stat_buf) == 0)
134 m_filestamp=stat_buf.st_mtime;
135 m_lock=RWLock::create();
138 log.debug("no file path/name supplied, will look for metadata inline");
141 FilesystemMetadataProvider::~FilesystemMetadataProvider()
147 void FilesystemMetadataProvider::init()
153 XMLObject* FilesystemMetadataProvider::load() const
158 Category& log=Category::getInstance(SAML_LOGCAT".Metadata");
161 XMLObject* xmlObject=NULL;
163 if (!m_source.empty()) {
164 // Data comes from a file we have to parse.
165 log.debug("loading metadata from file...");
166 auto_ptr_XMLCh widenit(m_source.c_str());
167 LocalFileInputSource src(widenit.get());
168 Wrapper4InputSource dsrc(&src,false);
169 DOMDocument* doc=NULL;
171 doc=XMLToolingConfig::getConfig().getValidatingParser().parse(dsrc);
173 doc=XMLToolingConfig::getConfig().getParser().parse(dsrc);
174 XercesJanitor<DOMDocument> docjanitor(doc);
175 log.infoStream() << "loaded and parsed XML file (" << m_source << ")" << CategoryStream::ENDLINE;
177 // Unmarshall objects, binding the document.
178 xmlObject = XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true);
179 docjanitor.release();
182 // Data comes from the DOM we were handed.
183 log.debug("loading inline metadata...");
184 DOMElement* child = XMLHelper::getFirstChildElement(m_root);
186 throw XMLToolingException("No metadata was found inline.");
187 xmlObject = XMLObjectBuilder::buildOneFromElement(child);
190 auto_ptr<XMLObject> xmlObjectPtr(xmlObject);
192 doFilters(*xmlObject);
194 xmlObjectPtr->releaseThisAndChildrenDOM();
195 xmlObjectPtr->setDocument(NULL);
196 return xmlObjectPtr.release();
198 catch (XMLException& e) {
199 auto_ptr_char msg(e.getMessage());
200 log.errorStream() << "Xerces parser error while loading metadata from ("
201 << (m_source.empty() ? "inline" : m_source) << "): " << msg.get() << CategoryStream::ENDLINE;
202 throw XMLParserException(msg.get());
204 catch (XMLToolingException& e) {
205 log.errorStream() << "error while loading metadata from ("
206 << (m_source.empty() ? "inline" : m_source) << "): " << e.what() << CategoryStream::ENDLINE;
211 Lockable* FilesystemMetadataProvider::lock()
218 // Check if we need to refresh.
220 struct _stat stat_buf;
221 if (_stat(m_source.c_str(), &stat_buf) == 0)
223 struct stat stat_buf;
224 if (stat(m_source.c_str(), &stat_buf) == 0)
227 if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime) {
228 // Elevate lock and recheck.
231 if (m_filestamp>0 && m_filestamp<stat_buf.st_mtime) {
232 SharedLock lockwrap(m_lock,false); // pops write lock
234 // Update the timestamp regardless. No point in repeatedly trying.
235 m_filestamp=stat_buf.st_mtime;
236 XMLObject* newstuff = load();
242 catch(XMLToolingException& e) {
243 Category::getInstance(SAML_LOGCAT".Metadata").error("failed to reload metadata from file, sticking with what we have: %s", e.what());
255 void FilesystemMetadataProvider::index()
257 clearDescriptorIndex();
258 EntitiesDescriptor* group=dynamic_cast<EntitiesDescriptor*>(m_object);
260 AbstractMetadataProvider::index(group, SAMLTIME_MAX);
263 EntityDescriptor* site=dynamic_cast<EntityDescriptor*>(m_object);
264 AbstractMetadataProvider::index(site, SAMLTIME_MAX);