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