Fail if any metadata provider fails.
[shibboleth/cpp-sp.git] / shib-target / shib-config.cpp
1 /*
2  * shib-config.cpp -- ShibTarget initialization and finalization routines
3  *
4  * Created By:  Derek Atkins <derek@ihtfp.com>
5  *
6  * $Id$
7  */
8
9 #include "shib-target.h"
10 #include "ccache-utils.h"
11 #include <shib/shib-threads.h>
12
13 #include <log4cpp/PropertyConfigurator.hh>
14 #include <log4cpp/Category.hh>
15
16 using namespace saml;
17 using namespace shibboleth;
18 using namespace shibtarget;
19 using namespace std;
20 using namespace log4cpp;
21
22 #ifndef SHIBTARGET_INIFILE
23 #define SHIBTARGET_INIFILE "/opt/shibboleth/etc/shibboleth/shibboleth.ini"
24 #endif
25
26 class STConfig : public ShibTargetConfig
27 {
28 public:
29   STConfig(const char* app_name, const char* inifile);
30   ~STConfig();
31   void shutdown();
32   void init();
33   ShibINI& getINI() { return *ini; }
34
35   Iterator<const XMLCh*> getPolicies() { return Iterator<const XMLCh*>(policies); }
36
37   void ref();
38 private:
39   SAMLConfig& samlConf;
40   ShibConfig& shibConf;
41   ShibINI* ini;
42   string m_app_name;
43   int refcount;
44   vector<const XMLCh*> policies;
45 };
46
47 namespace {
48   STConfig * g_Config = NULL;
49   Mutex * g_lock = NULL;
50 }
51
52 CCache* shibtarget::g_shibTargetCCache = NULL;
53
54 /****************************************************************************/
55 // External Interface
56
57
58 void ShibTargetConfig::preinit()
59 {
60   if (g_lock) return;
61   g_lock = Mutex::create();
62 }
63
64 ShibTargetConfig& ShibTargetConfig::init(const char* app_name, const char* inifile)
65 {
66   if (!g_lock)
67     throw runtime_error ("ShibTargetConfig not pre-initialized");
68
69   if (!app_name)
70     throw runtime_error ("No Application name");
71   Lock lock(g_lock);
72
73   if (g_Config) {
74     g_Config->ref();
75     return *g_Config;
76   }
77
78   g_Config = new STConfig(app_name, inifile);
79   g_Config->init();
80   return *g_Config;
81 }
82
83 ShibTargetConfig& ShibTargetConfig::getConfig()
84 {
85     if (!g_Config)
86         throw SAMLException("ShibTargetConfig::getConfig() called with NULL configuration");
87     return *g_Config;
88 }
89
90 ShibTargetConfig::~ShibTargetConfig()
91 {
92 #ifdef WIN32
93 #else
94     if (m_SocketName) free(m_SocketName);
95 #endif
96 }
97
98 /****************************************************************************/
99 // STConfig
100
101 STConfig::STConfig(const char* app_name, const char* inifile)
102   :  samlConf(SAMLConfig::getConfig()), shibConf(ShibConfig::getConfig()),
103      m_app_name(app_name)
104 {
105   try {
106     ini = new ShibINI((inifile ? inifile : SHIBTARGET_INIFILE));
107   } catch (...) {
108     cerr << "Unable to load the INI file: " << 
109       (inifile ? inifile : SHIBTARGET_INIFILE) << endl;
110     throw;
111   }
112 }
113
114 extern "C" SAMLAttribute* ScopedFactory(DOMElement* e)
115 {
116     return new ScopedAttribute(e);
117 }
118
119 extern "C" SAMLAttribute* SimpleFactory(DOMElement* e)
120 {
121     return new SimpleAttribute(e);
122 }
123
124 void STConfig::init()
125 {
126   string app = m_app_name;
127   string tag;
128
129   // Initialize Log4cpp
130   if (ini->get_tag (app, SHIBTARGET_TAG_LOGGER, true, &tag)) {
131     cerr << "Trying to load logger configuration: " << tag << "\n";
132     try {
133       PropertyConfigurator::configure(tag);
134     } catch (ConfigureFailure& e) {
135       cerr << "Error reading configuration: " << e.what() << "\n";
136     }
137   } else {
138     Category& category = Category::getRoot();
139     category.setPriority(log4cpp::Priority::DEBUG);
140     cerr << "No logger configuration found\n";
141   }
142
143   Category& log = Category::getInstance("shibtarget.STConfig");
144
145   saml::NDC ndc("STConfig::init");
146
147   // Init SAML Configuration
148   if (ini->get_tag (app, SHIBTARGET_TAG_SAMLCOMPAT, true, &tag))
149     samlConf.compatibility_mode = ShibINI::boolean(tag);
150   if (ini->get_tag (app, SHIBTARGET_TAG_SCHEMAS, true, &tag))
151     samlConf.schema_dir = tag;
152
153   // Init SAML Binding Configuration
154   if (ini->get_tag (app, SHIBTARGET_TAG_AATIMEOUT, true, &tag))
155     samlConf.binding_defaults.timeout = atoi(tag.c_str());
156   if (ini->get_tag (app, SHIBTARGET_TAG_AACONNECTTO, true, &tag))
157     samlConf.binding_defaults.conn_timeout = atoi(tag.c_str());
158   if (ini->get_tag (app, SHIBTARGET_TAG_CERTFILE, true, &tag))
159     samlConf.binding_defaults.ssl_certfile = tag;
160   if (ini->get_tag (app, SHIBTARGET_TAG_KEYFILE, true, &tag))
161     samlConf.binding_defaults.ssl_keyfile = tag;
162   if (ini->get_tag (app, SHIBTARGET_TAG_KEYPASS, true, &tag))
163     samlConf.binding_defaults.ssl_keypass = tag;
164   if (ini->get_tag (app, SHIBTARGET_TAG_CALIST, true, &tag))
165     samlConf.binding_defaults.ssl_calist = tag;
166
167   try {
168     if (!samlConf.init()) {
169       log.fatal ("Failed to initialize SAML Library");
170       throw runtime_error ("Failed to initialize SAML Library");
171     } else
172       log.debug ("SAML Initialized");
173   } catch (...) {
174     log.crit ("Died initializing SAML Library");
175     throw;    
176   }
177
178   // Init Shib
179   if (ini->get_tag(app, SHIBTARGET_TAG_AAP, true, &tag))
180       shibConf.aapFile=tag;
181
182   try { 
183     if (!shibConf.init()) {
184       log.fatal ("Failed to initialize Shib library");
185       throw runtime_error ("Failed to initialize Shib Library");
186     } else
187       log.debug ("Shib Initialized");
188   } catch (...) {
189     log.crit ("Failed initializing Shib library.");
190     throw;
191   }
192
193   // Load any SAML extensions
194   string ext = "extensions:saml";
195   if (ini->exists(ext)) {
196     saml::NDC ndc("load_extensions");
197     ShibINI::Iterator* iter = ini->tag_iterator(ext);
198
199     for (const string* str = iter->begin(); str; str = iter->next()) {
200       string file = ini->get(ext, *str);
201       try
202       {
203         samlConf.saml_register_extension(file.c_str(),ini);
204         log.debug("%s: loading %s", str->c_str(), file.c_str());
205       }
206       catch (SAMLException& e)
207       {
208         log.crit("%s: %s", str->c_str(), e.what());
209       }
210     }
211     delete iter;
212   }
213
214   // Load the specified metadata.
215   if (ini->get_tag(app, SHIBTARGET_TAG_METADATA, true, &tag) && ini->exists(tag))
216   {
217     ShibINI::Iterator* iter=ini->tag_iterator(tag);
218     for (const string* prov=iter->begin(); prov; prov=iter->next())
219     {
220         const string source=ini->get(tag,*prov);
221         log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
222         if (!shibConf.addMetadata(prov->c_str(),source.c_str()))
223         {
224             log.fatal("error adding metadata provider");
225             throw runtime_error("error adding metadata provider");
226         }
227     }
228     delete iter;
229   }
230   
231   // Register attributes based on built-in classes.
232   if (ini->exists("attributes")) {
233     log.info("registering attributes");
234     ShibINI::Iterator* iter=ini->tag_iterator("attributes");
235     for (const string* attrname=iter->begin(); attrname; attrname=iter->next())
236     {
237         const string factory=ini->get("attributes",*attrname);
238         if (factory=="scoped")
239         {
240             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
241             SAMLAttribute::regFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI,&ScopedFactory);
242             log.info("registered scoped attribute (%s)",attrname->c_str());
243         }
244         else if (factory=="simple")
245         {
246             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
247             SAMLAttribute::regFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI,&SimpleFactory);
248             log.info("registered simple attribute (%s)",attrname->c_str());
249         }
250     }
251         delete iter;
252   }
253
254   // Load SAML policies.
255   if (ini->exists(SHIBTARGET_POLICIES)) {
256     log.info("loading SAML policies");
257     ShibINI::Iterator* iter = ini->tag_iterator(SHIBTARGET_POLICIES);
258
259     for (const string* str = iter->begin(); str; str = iter->next()) {
260         policies.push_back(XMLString::transcode(ini->get(SHIBTARGET_POLICIES, *str).c_str()));
261     }
262     delete iter;
263   }
264   
265   // Initialize the SHAR Cache
266   if (!strcmp (app.c_str(), SHIBTARGET_SHAR)) {
267     const char * cache_type = NULL;
268     if (ini->get_tag (app, SHIBTARGET_TAG_CACHETYPE, true, &tag))
269       cache_type = tag.c_str();
270
271     g_shibTargetCCache = CCache::getInstance(cache_type);
272   }
273
274   string sockname=ini->get(SHIBTARGET_GENERAL, "sharsocket");
275 #ifdef WIN32
276   if (sockname.length()>0)
277     m_SocketName=atoi(sockname.c_str());
278   else
279     m_SocketName=SHIB_SHAR_SOCKET;
280 #else
281   if (sockname.length()>0)
282     m_SocketName=strdup(sockname.c_str());
283   else
284     m_SocketName=strdup(SHIB_SHAR_SOCKET);
285 #endif
286
287   ref();
288   log.debug("finished");
289 }
290
291 STConfig::~STConfig()
292 {
293   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
294     delete const_cast<XMLCh*>(*i);
295     
296   // Unregister attributes based on built-in classes.
297   if (ini && ini->exists("attributes")) {
298     ShibINI::Iterator* iter=ini->tag_iterator("attributes");
299     for (const string* attrname=iter->begin(); attrname; attrname=iter->next())
300     {
301         const string factory=ini->get("attributes",*attrname);
302         if (factory=="scoped")
303         {
304             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
305             SAMLAttribute::unregFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
306         }
307         else if (factory=="simple")
308         {
309             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
310             SAMLAttribute::unregFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
311         }
312     }
313         delete iter;
314   }
315
316   if (ini) delete ini;
317   
318   if (g_shibTargetCCache)
319     delete g_shibTargetCCache;
320
321   shibConf.term();
322   samlConf.term();
323 }
324
325 void STConfig::ref()
326 {
327   refcount++;
328 }
329
330 void STConfig::shutdown()
331 {
332   refcount--;
333   if (!refcount) {
334     delete g_Config;
335     g_Config = NULL;
336   }
337 }