Removed obsoleted "attributes" section.
[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 void STConfig::init()
115 {
116   string app = m_app_name;
117   string tag;
118
119   // Initialize Log4cpp
120   if (ini->get_tag (app, SHIBTARGET_TAG_LOGGER, true, &tag)) {
121     cerr << "Trying to load logger configuration: " << tag << "\n";
122     try {
123       PropertyConfigurator::configure(tag);
124     } catch (ConfigureFailure& e) {
125       cerr << "Error reading configuration: " << e.what() << "\n";
126     }
127   } else {
128     Category& category = Category::getRoot();
129     category.setPriority(log4cpp::Priority::DEBUG);
130     cerr << "No logger configuration found\n";
131   }
132
133   Category& log = Category::getInstance("shibtarget.STConfig");
134
135   saml::NDC ndc("STConfig::init");
136
137   // Init SAML Configuration
138   if (ini->get_tag (app, SHIBTARGET_TAG_SAMLCOMPAT, true, &tag))
139     samlConf.compatibility_mode = ShibINI::boolean(tag);
140   if (ini->get_tag (app, SHIBTARGET_TAG_SCHEMAS, true, &tag))
141     samlConf.schema_dir = tag;
142
143   // Init SAML Binding Configuration
144   if (ini->get_tag (app, SHIBTARGET_TAG_AATIMEOUT, true, &tag))
145     samlConf.binding_defaults.timeout = atoi(tag.c_str());
146   if (ini->get_tag (app, SHIBTARGET_TAG_AACONNECTTO, true, &tag))
147     samlConf.binding_defaults.conn_timeout = atoi(tag.c_str());
148   if (ini->get_tag (app, SHIBTARGET_TAG_CERTFILE, true, &tag))
149     samlConf.binding_defaults.ssl_certfile = tag;
150   if (ini->get_tag (app, SHIBTARGET_TAG_KEYFILE, true, &tag))
151     samlConf.binding_defaults.ssl_keyfile = tag;
152   if (ini->get_tag (app, SHIBTARGET_TAG_KEYPASS, true, &tag))
153     samlConf.binding_defaults.ssl_keypass = tag;
154   if (ini->get_tag (app, SHIBTARGET_TAG_CALIST, true, &tag))
155     samlConf.binding_defaults.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.aapFile=tag;
171
172   try { 
173     if (!shibConf.init()) {
174       log.fatal ("Failed to initialize Shib library");
175       throw runtime_error ("Failed to initialize Shib Library");
176     } else
177       log.debug ("Shib Initialized");
178   } catch (...) {
179     log.crit ("Failed initializing Shib library.");
180     throw;
181   }
182
183   // Load any SAML extensions
184   string ext = "extensions:saml";
185   if (ini->exists(ext)) {
186     saml::NDC ndc("load_extensions");
187     ShibINI::Iterator* iter = ini->tag_iterator(ext);
188
189     for (const string* str = iter->begin(); str; str = iter->next()) {
190       string file = ini->get(ext, *str);
191       try
192       {
193         samlConf.saml_register_extension(file.c_str(),ini);
194         log.debug("%s: loading %s", str->c_str(), file.c_str());
195       }
196       catch (SAMLException& e)
197       {
198         log.crit("%s: %s", str->c_str(), e.what());
199       }
200     }
201     delete iter;
202   }
203
204   // Load the specified metadata.
205   if (ini->get_tag(app, SHIBTARGET_TAG_METADATA, true, &tag) && ini->exists(tag))
206   {
207     ShibINI::Iterator* iter=ini->tag_iterator(tag);
208     for (const string* prov=iter->begin(); prov; prov=iter->next())
209     {
210         const string source=ini->get(tag,*prov);
211         log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
212         if (!shibConf.addMetadata(prov->c_str(),source.c_str()))
213         {
214             log.crit("error adding metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
215             if (!strcmp(app.c_str(), SHIBTARGET_SHAR))
216                 throw runtime_error("error adding metadata provider");
217         }
218     }
219     delete iter;
220   }
221   
222   // Load SAML policies.
223   if (ini->exists(SHIBTARGET_POLICIES)) {
224     log.info("loading SAML policies");
225     ShibINI::Iterator* iter = ini->tag_iterator(SHIBTARGET_POLICIES);
226
227     for (const string* str = iter->begin(); str; str = iter->next()) {
228         policies.push_back(XMLString::transcode(ini->get(SHIBTARGET_POLICIES, *str).c_str()));
229     }
230     delete iter;
231   }
232   
233   // Initialize the SHAR Cache
234   if (!strcmp (app.c_str(), SHIBTARGET_SHAR)) {
235     const char * cache_type = NULL;
236     if (ini->get_tag (app, SHIBTARGET_TAG_CACHETYPE, true, &tag))
237       cache_type = tag.c_str();
238
239     g_shibTargetCCache = CCache::getInstance(cache_type);
240   }
241
242   string sockname=ini->get(SHIBTARGET_GENERAL, "sharsocket");
243 #ifdef WIN32
244   if (sockname.length()>0)
245     m_SocketName=atoi(sockname.c_str());
246   else
247     m_SocketName=SHIB_SHAR_SOCKET;
248 #else
249   if (sockname.length()>0)
250     m_SocketName=strdup(sockname.c_str());
251   else
252     m_SocketName=strdup(SHIB_SHAR_SOCKET);
253 #endif
254
255   ref();
256   log.debug("finished");
257 }
258
259 STConfig::~STConfig()
260 {
261   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
262     delete const_cast<XMLCh*>(*i);
263     
264   if (ini) delete ini;
265   
266   if (g_shibTargetCCache)
267     delete g_shibTargetCCache;
268
269   shibConf.term();
270   samlConf.term();
271 }
272
273 void STConfig::ref()
274 {
275   refcount++;
276 }
277
278 void STConfig::shutdown()
279 {
280   refcount--;
281   if (!refcount) {
282     delete g_Config;
283     g_Config = NULL;
284   }
285 }