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