96a73141448150de362547c3f48101a6e4a1dd22
[shibboleth/cpp-sp.git] / shib / ShibConfig.cpp
1 /*
2  *  Copyright 2001-2005 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* ShibConfig.cpp - Shibboleth runtime configuration
18
19    Scott Cantor
20    6/4/02
21
22    $History:$
23 */
24
25 #include <time.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #define SHIB_INSTANTIATE
30
31 #include "internal.h"
32
33 #include <openssl/err.h>
34
35 using namespace saml;
36 using namespace shibboleth;
37 using namespace xmltooling;
38 using namespace log4cpp;
39 using namespace std;
40
41
42 SAML_EXCEPTION_FACTORY(ResourceAccessException);
43 SAML_EXCEPTION_FACTORY(MetadataException);
44 SAML_EXCEPTION_FACTORY(CredentialException);
45 SAML_EXCEPTION_FACTORY(InvalidHandleException);
46 SAML_EXCEPTION_FACTORY(InvalidSessionException);
47
48 PlugManager::Factory BasicTrustFactory;
49 PlugManager::Factory ShibbolethTrustFactory;
50
51 namespace {
52     ShibConfig g_config;
53     vector<Mutex*> g_openssl_locks;
54 #ifdef HAVE_GOOD_STL
55     map<xstring,const IAttributeFactory*> attrMap;
56 #else
57     map<XMLCh*,const IAttributeFactory*> attrMap;
58 #endif
59 }
60
61 extern "C" SAMLAttribute* ShibAttributeFactory(DOMElement* e)
62 {
63     // First check for an explicit factory.
64 #ifdef HAVE_GOOD_STL
65     map<xstring,const IAttributeFactory*>::const_iterator i=attrMap.find(e->getAttributeNS(NULL,L(AttributeName)));
66 #else
67     const XMLCh* aname=e->getAttributeNS(NULL,L(AttributeName));
68     map<XMLCh*,const IAttributeFactory*>::const_iterator i;
69     for (i=attrMap.begin(); i!=attrMap.end(); i++)
70         if (!XMLString::compareString(aname,i->first))
71             break;
72 #endif
73     if (i!=attrMap.end())
74         return i->second->build(e);
75
76     // Now check for a Scope attribute to ensure proper value handling whenever possible.
77     DOMElement* n=saml::XML::getFirstChildElement(e,saml::XML::SAML_NS,L(AttributeValue));
78     if (n && n->hasAttributeNS(NULL,ScopedAttribute::Scope))
79         return new ScopedAttribute(e);
80         
81     // Just use the default class.
82     return new SAMLAttribute(e);
83 }
84
85 void ShibConfig::regAttributeMapping(const XMLCh* name, const IAttributeFactory* factory)
86 {
87     if (name && factory) {
88 #ifdef HAVE_GOOD_STL
89         attrMap[name]=factory;
90 #else
91         attrMap.insert(make_pair(XMLString::replicate(name),factory));
92 #endif
93     }
94 }
95
96 void ShibConfig::unregAttributeMapping(const XMLCh* name)
97 {
98     if (name) {
99 #ifdef HAVE_GOOD_STL
100         attrMap.erase(name);
101 #else
102         for (map<XMLCh*,const IAttributeFactory*>::iterator i=attrMap.begin(); i!=attrMap.end(); i++) {
103             if (!XMLString::compareString(name,i->first)) {
104                 XMLCh* temp=i->first;
105                 XMLString::release(&temp);
106                 attrMap.erase(i);
107                 break;
108             }
109         }
110 #endif
111     }
112 }
113
114 void ShibConfig::clearAttributeMappings()
115 {
116 #ifndef HAVE_GOOD_STL
117     for (map<XMLCh*,const IAttributeFactory*>::iterator i=attrMap.begin(); i!=attrMap.end(); i++) {
118         XMLCh* temp=i->first;
119         XMLString::release(&temp);
120     }
121 #endif
122     attrMap.clear();
123 }
124
125 extern "C" void openssl_locking_callback(int mode,int n,const char *file,int line)
126 {
127     if (mode & CRYPTO_LOCK)
128         g_openssl_locks[n]->lock();
129     else
130         g_openssl_locks[n]->unlock();
131 }
132
133 #ifndef WIN32
134 extern "C" unsigned long openssl_thread_id(void)
135 {
136     return (unsigned long)(pthread_self());
137 }
138 #endif
139
140 bool ShibConfig::init()
141 {
142     REGISTER_EXCEPTION_FACTORY(ResourceAccessException);
143     REGISTER_EXCEPTION_FACTORY(MetadataException);
144     REGISTER_EXCEPTION_FACTORY(CredentialException);
145     REGISTER_EXCEPTION_FACTORY(InvalidHandleException);
146     REGISTER_EXCEPTION_FACTORY(InvalidSessionException);
147
148     // Register plugin factories (some are legacy aliases)
149     SAMLConfig& conf=SAMLConfig::getConfig();
150     conf.getPlugMgr().regFactory("edu.internet2.middleware.shibboleth.common.provider.BasicTrust",&BasicTrustFactory);
151     conf.getPlugMgr().regFactory("edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust",&ShibbolethTrustFactory);
152
153     // Set up OpenSSL locking.
154         for (int i=0; i<CRYPTO_num_locks(); i++)
155         g_openssl_locks.push_back(Mutex::create());
156         CRYPTO_set_locking_callback(openssl_locking_callback);
157 #ifndef WIN32
158     CRYPTO_set_id_callback(openssl_thread_id);
159 #endif
160
161     SAMLAttribute::setFactory(&ShibAttributeFactory);
162     return true;
163 }
164
165 void ShibConfig::term()
166 {
167     SAMLAttribute::setFactory(NULL);
168     clearAttributeMappings();
169    
170     CRYPTO_set_locking_callback(NULL);
171     for (vector<Mutex*>::iterator j=g_openssl_locks.begin(); j!=g_openssl_locks.end(); j++)
172         delete (*j);
173     g_openssl_locks.clear();
174
175     // Unregister plugin factories
176     SAMLConfig& conf=SAMLConfig::getConfig();
177     conf.getPlugMgr().unregFactory("edu.internet2.middleware.shibboleth.common.provider.BasicTrust");
178     conf.getPlugMgr().unregFactory("edu.internet2.middleware.shibboleth.common.provider.ShibbolethTrust");
179 }
180
181 ShibConfig& ShibConfig::getConfig()
182 {
183     return g_config;
184 }
185
186 void shibboleth::annotateException(SAMLException* e, const IEntityDescriptor* entity, bool rethrow)
187 {
188     if (entity) {
189         auto_ptr_char id(entity->getId());
190         e->addProperty("providerId",id.get());
191         Iterator<const IRoleDescriptor*> roles=entity->getRoleDescriptors();
192         while (roles.hasNext()) {
193             const IRoleDescriptor* role=roles.next();
194             if (role->isValid()) {
195                 const char* temp=role->getErrorURL();
196                 if (temp) {
197                     e->addProperty("errorURL",temp);
198                     break;
199                 }
200             }
201         }
202
203         Iterator<const IContactPerson*> i=entity->getContactPersons();
204         while (i.hasNext()) {
205             const IContactPerson* c=i.next();
206             if ((c->getType()==IContactPerson::technical || c->getType()==IContactPerson::support)) {
207                 const char* fname=c->getGivenName();
208                 const char* lname=c->getSurName();
209                 if (fname && lname) {
210                     string contact=string(fname) + ' ' + lname;
211                     e->addProperty("contactName",contact.c_str());
212                 }
213                 else if (fname)
214                     e->addProperty("contactName",fname);
215                 else if (lname)
216                     e->addProperty("contactName",lname);
217                 Iterator<string> emails=c->getEmailAddresses();
218                 if (emails.hasNext())
219                     e->addProperty("contactEmail",emails.next().c_str());
220                 break;
221             }
222         }
223     }
224     
225     if (rethrow)
226         e->raise();
227 }
228
229 void shibboleth::annotateException(saml::SAMLException* e, const IRoleDescriptor* role, bool rethrow)
230 {
231     if (role) {
232         auto_ptr_char id(role->getEntityDescriptor()->getId());
233         e->addProperty("providerId",id.get());
234         const char* temp=role->getErrorURL();
235         if (role->getErrorURL())
236             e->addProperty("errorURL",role->getErrorURL());
237
238         Iterator<const IContactPerson*> i=role->getContactPersons();
239         while (i.hasNext()) {
240             const IContactPerson* c=i.next();
241             if ((c->getType()==IContactPerson::technical || c->getType()==IContactPerson::support)) {
242                 const char* fname=c->getGivenName();
243                 const char* lname=c->getSurName();
244                 if (fname && lname) {
245                     string contact=string(fname) + ' ' + lname;
246                     e->addProperty("contactName",contact.c_str());
247                 }
248                 else if (fname)
249                     e->addProperty("contactName",fname);
250                 else if (lname)
251                     e->addProperty("contactName",lname);
252                 Iterator<string> emails=c->getEmailAddresses();
253                 if (emails.hasNext())
254                     e->addProperty("contactEmail",emails.next().c_str());
255                 break;
256             }
257         }
258     }
259     
260     if (rethrow)
261         e->raise();
262 }