Added new OriginSiteMapper design to support refresh.
[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   ShibINI& getINI() { return *ini; }
31
32   Iterator<const XMLCh*> getPolicies() { return Iterator<const XMLCh*>(policies); }
33
34   void ref();
35 private:
36   SAMLConfig& samlConf;
37   ShibConfig& shibConf;
38   ShibINI* ini;
39   int refcount;
40   vector<const XMLCh*> policies;
41 };
42
43 namespace {
44   STConfig * g_Config = NULL;
45   Mutex * g_lock = NULL;
46 }
47
48 CCache* shibtarget::g_shibTargetCCache = NULL;
49
50 /****************************************************************************/
51 // External Interface
52
53
54 void ShibTargetConfig::preinit()
55 {
56   if (g_lock) return;
57   g_lock = Mutex::create();
58 }
59
60 ShibTargetConfig& ShibTargetConfig::init(const char* app_name, const char* inifile)
61 {
62   if (!g_lock)
63     throw runtime_error ("ShibTargetConfig not pre-initialized");
64
65   if (!app_name)
66     throw runtime_error ("No Application name");
67
68   Lock lock(g_lock);
69
70   if (g_Config) {
71     g_Config->ref();
72     return *g_Config;
73   }
74
75   g_Config = new STConfig(app_name, inifile);
76   return *g_Config;
77 }
78
79 ShibTargetConfig& ShibTargetConfig::getConfig()
80 {
81     if (!g_Config)
82         throw SAMLException("ShibTargetConfig::getConfig() called with NULL configuration");
83     return *g_Config;
84 }
85
86 ShibTargetConfig::~ShibTargetConfig()
87 {
88 #ifdef WIN32
89 #else
90     if (m_SocketName) free(m_SocketName);
91 #endif
92 }
93
94 /****************************************************************************/
95 // STConfig
96
97 STConfig::STConfig(const char* app_name, const char* inifile)
98   :  samlConf(SAMLConfig::getConfig()), shibConf(ShibConfig::getConfig())
99 {
100   try {
101     ini = new ShibINI((inifile ? inifile : SHIBTARGET_INIFILE));
102   } catch (...) {
103     cerr << "Unable to load the INI file: " << 
104       (inifile ? inifile : SHIBTARGET_INIFILE) << endl;
105     throw;
106   }
107
108   string app = app_name;
109   string tag;
110
111   // Initialize Log4cpp
112   if (ini->get_tag (app, SHIBTARGET_TAG_LOGGER, true, &tag)) {
113     cerr << "Trying to load logger configuration: " << tag << "\n";
114     try {
115       log4cpp::PropertyConfigurator::configure(tag);
116     } catch (log4cpp::ConfigureFailure& e) {
117       cerr << "Error reading configuration: " << e.what() << "\n";
118     }
119   } else {
120     log4cpp::Category& category = log4cpp::Category::getRoot();
121     category.setPriority(log4cpp::Priority::DEBUG);
122     cerr << "No logger configuration found\n";
123   }
124
125   log4cpp::Category& log = log4cpp::Category::getInstance("shibtarget.STConfig");
126
127   // Init SAML
128   if (ini->get_tag (app, SHIBTARGET_TAG_SCHEMAS, true, &tag))
129     samlConf.schema_dir = tag;
130   if (ini->get_tag (app, SHIBTARGET_TAG_CERTFILE, true, &tag))
131     samlConf.ssl_certfile = tag;
132   if (ini->get_tag (app, SHIBTARGET_TAG_KEYFILE, true, &tag))
133     samlConf.ssl_keyfile = tag;
134   if (ini->get_tag (app, SHIBTARGET_TAG_KEYPASS, true, &tag))
135     samlConf.ssl_keypass = tag;
136   if (ini->get_tag (app, SHIBTARGET_TAG_CALIST, true, &tag))
137     samlConf.ssl_calist = tag;
138
139   try {
140     if (!samlConf.init()) {
141       log.fatal ("Failed to initialize SAML Library");
142       throw runtime_error ("Failed to initialize SAML Library");
143     } else
144       log.debug ("SAML Initialized");
145   } catch (...) {
146     log.crit ("Died initializing SAML Library");
147     throw;    
148   }
149
150   // Init Shib
151   if (! ini->get_tag (app, SHIBTARGET_TAG_SITES, true, &tag)) {
152     log.fatal("No Sites File found in configuration");
153     throw runtime_error ("No Sites File found in configuration");
154   }
155
156   shibConf.mapperURL=tag;
157   try {
158     if (ini->get_tag (app, SHIBTARGET_TAG_SITESCERT, true, &tag)) {
159       shibConf.mapperCert = new X509Certificate (X509Certificate::PEM, tag.c_str());
160     }
161   } catch (...) {
162     log.crit ("Can not read the x509 certificate.");
163     throw;
164   }
165
166   try { 
167     if (!shibConf.init()) {
168       log.fatal ("Failed to initialize Shib library");
169       throw runtime_error ("Failed to initialize Shib Library");
170     } else
171       log.debug ("Shib Initialized");
172   } catch (...) {
173     log.crit ("Failed initializing Shib library.");
174     throw;
175   }
176
177   // Initialize the SHAR Cache
178   if (!strcmp (app_name, SHIBTARGET_SHAR))
179     g_shibTargetCCache = CCache::getInstance(NULL);
180
181   // Load any SAML extensions
182   string ext = "extensions:saml";
183   if (ini->exists(ext)) {
184     saml::NDC ndc("load extensions");
185     ShibINI::Iterator* iter = ini->tag_iterator(ext);
186
187     for (const string* str = iter->begin(); str; str = iter->next()) {
188       string file = ini->get(ext, *str);
189       try
190       {
191         samlConf.saml_register_extension(file.c_str(),ini);
192         log.debug("%s: loading %s", str->c_str(), file.c_str());
193       }
194       catch (SAMLException& e)
195       {
196         log.crit("%s: %s", str->c_str(), e.what());
197       }
198     }
199     delete iter;
200   }
201
202   // Load SAML policies.
203   if (ini->exists(ext)) {
204     log.debug("loading SAML policies");
205     ShibINI::Iterator* iter = ini->tag_iterator(SHIBTARGET_POLICIES);
206
207     for (const string* str = iter->begin(); str; str = iter->next()) {
208         policies.push_back(XMLString::transcode(ini->get(ext, *str).c_str()));
209     }
210     delete iter;
211   }
212   
213   string sockname=ini->get(SHIBTARGET_GENERAL, "sharsocket");
214 #ifdef WIN32
215   if (sockname.length()>0)
216     m_SocketName=atoi(sockname.c_str());
217   else
218     m_SocketName=SHIB_SHAR_SOCKET;
219 #else
220   if (sockname.length()>0)
221     m_SocketName=strdup(sockname.c_str());
222   else
223     m_SocketName=strdup(SHIB_SHAR_SOCKET);
224 #endif
225
226   ref();
227   log.debug("finished");
228 }
229
230 STConfig::~STConfig()
231 {
232   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
233     delete const_cast<XMLCh*>(*i);
234     
235   if (ini) delete ini;
236   
237   if (g_shibTargetCCache)
238     delete g_shibTargetCCache;
239
240   shibConf.term();
241   samlConf.term();
242 }
243
244 void STConfig::ref()
245 {
246   refcount++;
247 }
248
249 void STConfig::shutdown()
250 {
251   refcount--;
252   if (!refcount) {
253     delete g_Config;
254     g_Config = NULL;
255   }
256 }