7a4585b26ae2f7f9436e012947928c5e2ae2f9e2
[shibboleth/sp.git] / shibsp / SPConfig.cpp
1
2 /*
3  *  Copyright 2001-2010 Internet2
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 /**
19  * SPConfig.cpp
20  *
21  * Library configuration.
22  */
23
24 #include "internal.h"
25
26 #if defined(XMLTOOLING_LOG4SHIB)
27 # ifndef SHIBSP_LOG4SHIB
28 #  error "Logging library mismatch (XMLTooling is using log4shib)."
29 # endif
30 #elif defined(XMLTOOLING_LOG4CPP)
31 # ifndef SHIBSP_LOG4CPP
32 #  error "Logging library mismatch (XMLTooling is using log4cpp)."
33 # endif
34 #else
35 # error "No supported logging library."
36 #endif
37
38 #include "AccessControl.h"
39 #include "exceptions.h"
40 #include "RequestMapper.h"
41 #include "ServiceProvider.h"
42 #include "SessionCache.h"
43 #include "SPConfig.h"
44 #include "TransactionLog.h"
45 #include "attribute/Attribute.h"
46 #include "handler/SessionInitiator.h"
47 #include "remoting/ListenerService.h"
48
49 #ifndef SHIBSP_LITE
50 # include "attribute/AttributeDecoder.h"
51 # include "attribute/filtering/AttributeFilter.h"
52 # include "attribute/filtering/MatchFunctor.h"
53 # include "attribute/resolver/AttributeExtractor.h"
54 # include "attribute/resolver/AttributeResolver.h"
55 # include "binding/ArtifactResolver.h"
56 # include "metadata/MetadataExt.h"
57 # include "security/PKIXTrustEngine.h"
58 # include <saml/SAMLConfig.h>
59 #endif
60
61 #include <ctime>
62 #include <xercesc/util/XMLUniDefs.hpp>
63 #include <xmltooling/XMLToolingConfig.h>
64 #include <xmltooling/util/NDC.h>
65 #include <xmltooling/util/ParserPool.h>
66 #include <xmltooling/util/PathResolver.h>
67 #include <xmltooling/util/TemplateEngine.h>
68 #include <xmltooling/util/Threads.h>
69 #include <xmltooling/util/XMLHelper.h>
70
71 using namespace shibsp;
72 using namespace opensaml;
73 using namespace xmltooling;
74 using namespace std;
75
76 DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeException,shibsp);
77 DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeExtractionException,shibsp);
78 DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeFilteringException,shibsp);
79 DECL_XMLTOOLING_EXCEPTION_FACTORY(AttributeResolutionException,shibsp);
80 DECL_XMLTOOLING_EXCEPTION_FACTORY(ConfigurationException,shibsp);
81 DECL_XMLTOOLING_EXCEPTION_FACTORY(ListenerException,shibsp);
82
83 #ifdef SHIBSP_LITE
84 DECL_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
85 DECL_XMLTOOLING_EXCEPTION_FACTORY(SecurityPolicyException,opensaml);
86 DECL_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
87 DECL_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
88 DECL_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
89 DECL_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
90 #endif
91
92 namespace shibsp {
93    SPConfig g_config;
94 }
95
96 SPConfig& SPConfig::getConfig()
97 {
98     return g_config;
99 }
100
101 SPConfig::SPConfig() : attribute_value_delimeter(';'), m_serviceProvider(nullptr),
102 #ifndef SHIBSP_LITE
103     m_artifactResolver(nullptr),
104 #endif
105     m_features(0), m_configDoc(nullptr)
106 {
107 }
108
109 SPConfig::~SPConfig()
110 {
111 }
112
113 void SPConfig::setFeatures(unsigned long enabled)
114 {
115     m_features = enabled;
116 }
117
118 bool SPConfig::isEnabled(components_t feature)
119 {
120     return (m_features & feature)>0;
121 }
122
123 ServiceProvider* SPConfig::getServiceProvider() const
124 {
125     return m_serviceProvider;
126 }
127
128 void SPConfig::setServiceProvider(ServiceProvider* serviceProvider)
129 {
130     delete m_serviceProvider;
131     m_serviceProvider = serviceProvider;
132 }
133
134 #ifndef SHIBSP_LITE
135 void SPConfig::setArtifactResolver(MessageDecoder::ArtifactResolver* artifactResolver)
136 {
137     delete m_artifactResolver;
138     m_artifactResolver = artifactResolver;
139 }
140
141 const MessageDecoder::ArtifactResolver* SPConfig::getArtifactResolver() const
142 {
143     return m_artifactResolver;
144 }
145 #endif
146
147 bool SPConfig::init(const char* catalog_path, const char* inst_prefix)
148 {
149 #ifdef _DEBUG
150     NDC ndc("init");
151 #endif
152     if (!inst_prefix)
153         inst_prefix = getenv("SHIBSP_PREFIX");
154     if (!inst_prefix)
155         inst_prefix = SHIBSP_PREFIX;
156     std::string inst_prefix2;
157     while (*inst_prefix) {
158         inst_prefix2.push_back((*inst_prefix=='\\') ? ('/') : (*inst_prefix));
159         ++inst_prefix;
160     }
161
162     const char* loglevel=getenv("SHIBSP_LOGGING");
163     if (!loglevel)
164         loglevel = SHIBSP_LOGGING;
165     std::string ll(loglevel);
166     PathResolver localpr;
167     localpr.setDefaultPrefix(inst_prefix2.c_str());
168     inst_prefix = getenv("SHIBSP_CFGDIR");
169     if (!inst_prefix)
170         inst_prefix = SHIBSP_CFGDIR;
171     localpr.setCfgDir(inst_prefix);
172     XMLToolingConfig::getConfig().log_config(localpr.resolve(ll, PathResolver::XMLTOOLING_CFG_FILE, PACKAGE_NAME).c_str());
173
174     Category& log=Category::getInstance(SHIBSP_LOGCAT".Config");
175     log.debug("%s library initialization started", PACKAGE_STRING);
176
177     if (!catalog_path)
178         catalog_path = getenv("SHIBSP_SCHEMAS");
179     if (!catalog_path)
180         catalog_path = SHIBSP_SCHEMAS;
181     XMLToolingConfig::getConfig().catalog_path = catalog_path;
182
183 #ifndef SHIBSP_LITE
184     if (!SAMLConfig::getConfig().init()) {
185         log.fatal("failed to initialize OpenSAML library");
186         return false;
187     }
188 #else
189     if (!XMLToolingConfig::getConfig().init()) {
190         log.fatal("failed to initialize XMLTooling library");
191         return false;
192     }
193 #endif
194     PathResolver* pr = XMLToolingConfig::getConfig().getPathResolver();
195     pr->setDefaultPackageName(PACKAGE_NAME);
196     pr->setDefaultPrefix(inst_prefix2.c_str());
197     pr->setCfgDir(inst_prefix);
198     inst_prefix = getenv("SHIBSP_LIBDIR");
199     if (!inst_prefix)
200         inst_prefix = SHIBSP_LIBDIR;
201     pr->setLibDir(inst_prefix);
202     inst_prefix = getenv("SHIBSP_LOGDIR");
203     if (!inst_prefix)
204         inst_prefix = SHIBSP_LOGDIR;
205     pr->setLogDir(inst_prefix);
206     inst_prefix = getenv("SHIBSP_RUNDIR");
207     if (!inst_prefix)
208         inst_prefix = SHIBSP_RUNDIR;
209     pr->setRunDir(inst_prefix);
210     inst_prefix = getenv("SHIBSP_XMLDIR");
211     if (!inst_prefix)
212         inst_prefix = SHIBSP_XMLDIR;
213     pr->setXMLDir(inst_prefix);
214
215     XMLToolingConfig::getConfig().setTemplateEngine(new TemplateEngine());
216     XMLToolingConfig::getConfig().getTemplateEngine()->setTagPrefix("shibmlp");
217
218     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeException,shibsp);
219     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeExtractionException,shibsp);
220     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeFilteringException,shibsp);
221     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(AttributeResolutionException,shibsp);
222     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ConfigurationException,shibsp);
223     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ListenerException,shibsp);
224
225 #ifdef SHIBSP_LITE
226     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(BindingException,opensaml);
227     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(SecurityPolicyException,opensaml);
228     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(ProfileException,opensaml);
229     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(FatalProfileException,opensaml);
230     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(RetryableProfileException,opensaml);
231     REGISTER_XMLTOOLING_EXCEPTION_FACTORY(MetadataException,opensaml::saml2md);
232 #endif
233
234 #ifndef SHIBSP_LITE
235     if (isEnabled(Metadata))
236         registerMetadataExtClasses();
237     if (isEnabled(Trust))
238         registerPKIXTrustEngine();
239 #endif
240
241     registerAttributeFactories();
242     registerHandlers();
243     registerSessionInitiators();
244     registerServiceProviders();
245
246 #ifndef SHIBSP_LITE
247     if (isEnabled(AttributeResolution)) {
248         registerAttributeExtractors();
249         registerAttributeDecoders();
250         registerAttributeResolvers();
251         registerAttributeFilters();
252         registerMatchFunctors();
253     }
254 #endif
255
256     if (isEnabled(Listener))
257         registerListenerServices();
258
259     if (isEnabled(RequestMapping)) {
260         registerAccessControls();
261         registerRequestMappers();
262     }
263
264     if (isEnabled(Caching))
265         registerSessionCaches();
266
267 #ifndef SHIBSP_LITE
268     if (isEnabled(OutOfProcess))
269         m_artifactResolver = new ArtifactResolver();
270 #endif
271     srand(static_cast<unsigned int>(std::time(nullptr)));
272
273     log.info("%s library initialization complete", PACKAGE_STRING);
274     return true;
275 }
276
277 void SPConfig::term()
278 {
279 #ifdef _DEBUG
280     NDC ndc("term");
281 #endif
282     Category& log=Category::getInstance(SHIBSP_LOGCAT".Config");
283     log.info("%s library shutting down", PACKAGE_STRING);
284
285     setServiceProvider(nullptr);
286     if (m_configDoc)
287         m_configDoc->release();
288     m_configDoc = nullptr;
289 #ifndef SHIBSP_LITE
290     setArtifactResolver(nullptr);
291 #endif
292
293     ArtifactResolutionServiceManager.deregisterFactories();
294     AssertionConsumerServiceManager.deregisterFactories();
295     LogoutInitiatorManager.deregisterFactories();
296     ManageNameIDServiceManager.deregisterFactories();
297     SessionInitiatorManager.deregisterFactories();
298     SingleLogoutServiceManager.deregisterFactories();
299     HandlerManager.deregisterFactories();
300     ServiceProviderManager.deregisterFactories();
301     Attribute::deregisterFactories();
302
303 #ifndef SHIBSP_LITE
304     if (isEnabled(AttributeResolution)) {
305         MatchFunctorManager.deregisterFactories();
306         AttributeFilterManager.deregisterFactories();
307         AttributeDecoderManager.deregisterFactories();
308         AttributeExtractorManager.deregisterFactories();
309         AttributeResolverManager.deregisterFactories();
310     }
311 #endif
312
313     if (isEnabled(Listener))
314         ListenerServiceManager.deregisterFactories();
315
316     if (isEnabled(RequestMapping)) {
317         AccessControlManager.deregisterFactories();
318         RequestMapperManager.deregisterFactories();
319     }
320
321     if (isEnabled(Caching))
322         SessionCacheManager.deregisterFactories();
323
324 #ifndef SHIBSP_LITE
325     SAMLConfig::getConfig().term();
326 #else
327     XMLToolingConfig::getConfig().term();
328 #endif
329     log.info("%s library shutdown complete", PACKAGE_STRING);
330 }
331
332 bool SPConfig::instantiate(const char* config, bool rethrow)
333 {
334 #ifdef _DEBUG
335     NDC ndc("instantiate");
336 #endif
337     if (!config)
338         config = getenv("SHIBSP_CONFIG");
339     if (!config)
340         config = SHIBSP_CONFIG;
341     try {
342         xercesc::DOMDocument* dummydoc;
343         if (*config == '"' || *config == '\'') {
344             throw ConfigurationException("The value of SHIBSP_CONFIG started with a quote.");
345         }
346         else if (*config != '<') {
347
348             // Mock up some XML.
349             string resolved(config);
350             stringstream snippet;
351             snippet
352                 << "<Dummy path='"
353                 << XMLToolingConfig::getConfig().getPathResolver()->resolve(resolved, PathResolver::XMLTOOLING_CFG_FILE)
354                 << "' validate='1'/>";
355             dummydoc = XMLToolingConfig::getConfig().getParser().parse(snippet);
356             XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);
357             setServiceProvider(ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER, dummydoc->getDocumentElement()));
358             if (m_configDoc)
359                 m_configDoc->release();
360             m_configDoc = docjanitor.release();
361         }
362         else {
363             stringstream snippet(config);
364             dummydoc = XMLToolingConfig::getConfig().getParser().parse(snippet);
365             XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);
366             static const XMLCh _type[] = UNICODE_LITERAL_4(t,y,p,e);
367             auto_ptr_char type(dummydoc->getDocumentElement()->getAttributeNS(nullptr,_type));
368             if (type.get() && *type.get())
369                 setServiceProvider(ServiceProviderManager.newPlugin(type.get(), dummydoc->getDocumentElement()));
370             else
371                 throw ConfigurationException("The supplied XML bootstrapping configuration did not include a type attribute.");
372             if (m_configDoc)
373                 m_configDoc->release();
374             m_configDoc = docjanitor.release();
375         }
376
377         getServiceProvider()->init();
378         return true;
379     }
380     catch (exception& ex) {
381         if (rethrow)
382             throw;
383         Category::getInstance(SHIBSP_LOGCAT".Config").fatal("caught exception while loading configuration: %s", ex.what());
384     }
385     return false;
386 }
387
388 TransactionLog::TransactionLog() : log(logging::Category::getInstance(SHIBSP_TX_LOGCAT)), m_lock(Mutex::create())
389 {
390 }
391
392 TransactionLog::~TransactionLog()
393 {
394     delete m_lock;
395 }
396
397 Lockable* TransactionLog::lock()
398 {
399     m_lock->lock();
400     return this;
401 }
402
403 void TransactionLog::unlock()
404 {
405     m_lock->unlock();
406 }