Abort shar on metadata failure.
[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.crit("error adding metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
225             if (!strcmp(app.c_str(), SHIBTARGET_SHAR))
226                 throw runtime_error("error adding metadata provider");
227         }
228     }
229     delete iter;
230   }
231   
232   // Register attributes based on built-in classes.
233   if (ini->exists("attributes")) {
234     log.info("registering attributes");
235     ShibINI::Iterator* iter=ini->tag_iterator("attributes");
236     for (const string* attrname=iter->begin(); attrname; attrname=iter->next())
237     {
238         const string factory=ini->get("attributes",*attrname);
239         if (factory=="scoped")
240         {
241             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
242             SAMLAttribute::regFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI,&ScopedFactory);
243             log.info("registered scoped attribute (%s)",attrname->c_str());
244         }
245         else if (factory=="simple")
246         {
247             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
248             SAMLAttribute::regFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI,&SimpleFactory);
249             log.info("registered simple attribute (%s)",attrname->c_str());
250         }
251     }
252         delete iter;
253   }
254
255   // Load SAML policies.
256   if (ini->exists(SHIBTARGET_POLICIES)) {
257     log.info("loading SAML policies");
258     ShibINI::Iterator* iter = ini->tag_iterator(SHIBTARGET_POLICIES);
259
260     for (const string* str = iter->begin(); str; str = iter->next()) {
261         policies.push_back(XMLString::transcode(ini->get(SHIBTARGET_POLICIES, *str).c_str()));
262     }
263     delete iter;
264   }
265   
266   // Initialize the SHAR Cache
267   if (!strcmp (app.c_str(), SHIBTARGET_SHAR)) {
268     const char * cache_type = NULL;
269     if (ini->get_tag (app, SHIBTARGET_TAG_CACHETYPE, true, &tag))
270       cache_type = tag.c_str();
271
272     g_shibTargetCCache = CCache::getInstance(cache_type);
273   }
274
275   string sockname=ini->get(SHIBTARGET_GENERAL, "sharsocket");
276 #ifdef WIN32
277   if (sockname.length()>0)
278     m_SocketName=atoi(sockname.c_str());
279   else
280     m_SocketName=SHIB_SHAR_SOCKET;
281 #else
282   if (sockname.length()>0)
283     m_SocketName=strdup(sockname.c_str());
284   else
285     m_SocketName=strdup(SHIB_SHAR_SOCKET);
286 #endif
287
288   ref();
289   log.debug("finished");
290 }
291
292 STConfig::~STConfig()
293 {
294   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
295     delete const_cast<XMLCh*>(*i);
296     
297   // Unregister attributes based on built-in classes.
298   if (ini && ini->exists("attributes")) {
299     ShibINI::Iterator* iter=ini->tag_iterator("attributes");
300     for (const string* attrname=iter->begin(); attrname; attrname=iter->next())
301     {
302         const string factory=ini->get("attributes",*attrname);
303         if (factory=="scoped")
304         {
305             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
306             SAMLAttribute::unregFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
307         }
308         else if (factory=="simple")
309         {
310             auto_ptr<XMLCh> temp(XMLString::transcode(attrname->c_str()));
311             SAMLAttribute::unregFactory(temp.get(),shibboleth::Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
312         }
313     }
314         delete iter;
315   }
316
317   if (ini) delete ini;
318   
319   if (g_shibTargetCCache)
320     delete g_shibTargetCCache;
321
322   shibConf.term();
323   samlConf.term();
324 }
325
326 void STConfig::ref()
327 {
328   refcount++;
329 }
330
331 void STConfig::shutdown()
332 {
333   refcount--;
334   if (!refcount) {
335     delete g_Config;
336     g_Config = NULL;
337   }
338 }