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