Attribute filtering code.
[shibboleth/sp.git] / shibsp / impl / XMLServiceProvider.cpp
1 /*\r
2  *  Copyright 2001-2007 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * XMLServiceProvider.cpp\r
19  *\r
20  * XML-based SP configuration and mgmt\r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "exceptions.h"\r
25 #include "AccessControl.h"\r
26 #include "Application.h"\r
27 #include "RequestMapper.h"\r
28 #include "ServiceProvider.h"\r
29 #include "SessionCache.h"\r
30 #include "SPConfig.h"\r
31 #include "SPRequest.h"\r
32 #include "TransactionLog.h"\r
33 #include "attribute/filtering/AttributeFilter.h"\r
34 #include "attribute/resolver/AttributeExtractor.h"\r
35 #include "attribute/resolver/AttributeResolver.h"\r
36 #include "handler/SessionInitiator.h"\r
37 #include "remoting/ListenerService.h"\r
38 #include "security/PKIXTrustEngine.h"\r
39 #include "util/DOMPropertySet.h"\r
40 #include "util/SPConstants.h"\r
41 \r
42 #include <sys/types.h>\r
43 #include <sys/stat.h>\r
44 #include <log4cpp/Category.hh>\r
45 #include <log4cpp/PropertyConfigurator.hh>\r
46 #include <saml/SAMLConfig.h>\r
47 #include <saml/binding/ArtifactMap.h>\r
48 #include <saml/saml1/core/Assertions.h>\r
49 #include <saml/saml2/metadata/ChainingMetadataProvider.h>\r
50 #include <xmltooling/XMLToolingConfig.h>\r
51 #include <xmltooling/security/ChainingTrustEngine.h>\r
52 #include <xmltooling/util/NDC.h>\r
53 #include <xmltooling/util/ReloadableXMLFile.h>\r
54 #include <xmltooling/util/ReplayCache.h>\r
55 \r
56 using namespace shibsp;\r
57 using namespace opensaml::saml2;\r
58 using namespace opensaml::saml2md;\r
59 using namespace opensaml;\r
60 using namespace xmltooling;\r
61 using namespace log4cpp;\r
62 using namespace std;\r
63 \r
64 namespace {\r
65 \r
66 #if defined (_MSC_VER)\r
67     #pragma warning( push )\r
68     #pragma warning( disable : 4250 )\r
69 #endif\r
70 \r
71     static vector<const Handler*> g_noHandlers;\r
72 \r
73     // Application configuration wrapper\r
74     class SHIBSP_DLLLOCAL XMLApplication : public virtual Application, public DOMPropertySet, public DOMNodeFilter\r
75     {\r
76     public:\r
77         XMLApplication(const ServiceProvider*, const DOMElement* e, const XMLApplication* base=NULL);\r
78         ~XMLApplication() { cleanup(); }\r
79     \r
80         // Application\r
81         const ServiceProvider& getServiceProvider() const {return *m_sp;}\r
82         const char* getId() const {return getString("id").second;}\r
83         const char* getHash() const {return m_hash.c_str();}\r
84 \r
85         MetadataProvider* getMetadataProvider() const {\r
86             return (!m_metadata && m_base) ? m_base->getMetadataProvider() : m_metadata;\r
87         }\r
88         TrustEngine* getTrustEngine() const {\r
89             return (!m_trust && m_base) ? m_base->getTrustEngine() : m_trust;\r
90         }\r
91         AttributeExtractor* getAttributeExtractor() const {\r
92             return (!m_attrExtractor && m_base) ? m_base->getAttributeExtractor() : m_attrExtractor;\r
93         }\r
94         AttributeFilter* getAttributeFilter() const {\r
95             return (!m_attrFilter && m_base) ? m_base->getAttributeFilter() : m_attrFilter;\r
96         }\r
97         AttributeResolver* getAttributeResolver() const {\r
98             return (!m_attrResolver && m_base) ? m_base->getAttributeResolver() : m_attrResolver;\r
99         }\r
100         CredentialResolver* getCredentialResolver() const {\r
101             return (!m_credResolver && m_base) ? m_base->getCredentialResolver() : m_credResolver;\r
102         }\r
103         const PropertySet* getRelyingParty(const EntityDescriptor* provider) const;\r
104 \r
105         const SessionInitiator* getDefaultSessionInitiator() const;\r
106         const SessionInitiator* getSessionInitiatorById(const char* id) const;\r
107         const Handler* getDefaultAssertionConsumerService() const;\r
108         const Handler* getAssertionConsumerServiceByIndex(unsigned short index) const;\r
109         const vector<const Handler*>& getAssertionConsumerServicesByBinding(const XMLCh* binding) const;\r
110         const Handler* getHandler(const char* path) const;\r
111 \r
112         const vector<const XMLCh*>& getAudiences() const {\r
113             return (m_audiences.empty() && m_base) ? m_base->getAudiences() : m_audiences;\r
114         }\r
115 \r
116         // Provides filter to exclude special config elements.\r
117         short acceptNode(const DOMNode* node) const;\r
118     \r
119     private:\r
120         void cleanup();\r
121         const ServiceProvider* m_sp;   // this is ok because its locking scope includes us\r
122         const XMLApplication* m_base;\r
123         string m_hash;\r
124         MetadataProvider* m_metadata;\r
125         TrustEngine* m_trust;\r
126         AttributeExtractor* m_attrExtractor;\r
127         AttributeFilter* m_attrFilter;\r
128         AttributeResolver* m_attrResolver;\r
129         CredentialResolver* m_credResolver;\r
130         vector<const XMLCh*> m_audiences;\r
131 \r
132         // manage handler objects\r
133         vector<Handler*> m_handlers;\r
134 \r
135         // maps location (path info) to applicable handlers\r
136         map<string,const Handler*> m_handlerMap;\r
137 \r
138         // maps unique indexes to consumer services\r
139         map<unsigned int,const Handler*> m_acsIndexMap;\r
140         \r
141         // pointer to default consumer service\r
142         const Handler* m_acsDefault;\r
143 \r
144         // maps binding strings to supporting consumer service(s)\r
145 #ifdef HAVE_GOOD_STL\r
146         typedef map<xstring,vector<const Handler*> > ACSBindingMap;\r
147 #else\r
148         typedef map<string,vector<const Handler*> > ACSBindingMap;\r
149 #endif\r
150         ACSBindingMap m_acsBindingMap;\r
151 \r
152         // pointer to default session initiator\r
153         const SessionInitiator* m_sessionInitDefault;\r
154 \r
155         // maps unique ID strings to session initiators\r
156         map<string,const SessionInitiator*> m_sessionInitMap;\r
157 \r
158         // RelyingParty properties\r
159         DOMPropertySet* m_partyDefault;\r
160 #ifdef HAVE_GOOD_STL\r
161         map<xstring,PropertySet*> m_partyMap;\r
162 #else\r
163         map<const XMLCh*,PropertySet*> m_partyMap;\r
164 #endif\r
165     };\r
166 \r
167     // Top-level configuration implementation\r
168     class SHIBSP_DLLLOCAL XMLConfig;\r
169     class SHIBSP_DLLLOCAL XMLConfigImpl : public DOMPropertySet, public DOMNodeFilter\r
170     {\r
171     public:\r
172         XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log);\r
173         ~XMLConfigImpl();\r
174         \r
175         RequestMapper* m_requestMapper;\r
176         map<string,Application*> m_appmap;\r
177         map< string,pair< PropertySet*,vector<const SecurityPolicyRule*> > > m_policyMap;\r
178         \r
179         // Provides filter to exclude special config elements.\r
180         short acceptNode(const DOMNode* node) const;\r
181 \r
182         void setDocument(DOMDocument* doc) {\r
183             m_document = doc;\r
184         }\r
185 \r
186     private:\r
187         void doExtensions(const DOMElement* e, const char* label, Category& log);\r
188 \r
189         const XMLConfig* m_outer;\r
190         DOMDocument* m_document;\r
191     };\r
192 \r
193     class SHIBSP_DLLLOCAL XMLConfig : public ServiceProvider, public ReloadableXMLFile\r
194     {\r
195     public:\r
196         XMLConfig(const DOMElement* e) : ReloadableXMLFile(e, Category::getInstance(SHIBSP_LOGCAT".Config")),\r
197             m_impl(NULL), m_listener(NULL), m_sessionCache(NULL), m_tranLog(NULL) {\r
198         }\r
199         \r
200         void init() {\r
201             load();\r
202         }\r
203 \r
204         ~XMLConfig() {\r
205             delete m_impl;\r
206             delete m_sessionCache;\r
207             delete m_listener;\r
208             delete m_tranLog;\r
209             XMLToolingConfig::getConfig().setReplayCache(NULL);\r
210             SAMLConfig::getConfig().setArtifactMap(NULL);\r
211             for_each(m_storage.begin(), m_storage.end(), cleanup_pair<string,StorageService>());\r
212         }\r
213 \r
214         // PropertySet\r
215         void setParent(const PropertySet* parent) {return m_impl->setParent(parent);}\r
216         pair<bool,bool> getBool(const char* name, const char* ns=NULL) const {return m_impl->getBool(name,ns);}\r
217         pair<bool,const char*> getString(const char* name, const char* ns=NULL) const {return m_impl->getString(name,ns);}\r
218         pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const {return m_impl->getXMLString(name,ns);}\r
219         pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const {return m_impl->getUnsignedInt(name,ns);}\r
220         pair<bool,int> getInt(const char* name, const char* ns=NULL) const {return m_impl->getInt(name,ns);}\r
221         const PropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:2.0:native:sp:config") const {return m_impl->getPropertySet(name,ns);}\r
222         const DOMElement* getElement() const {return m_impl->getElement();}\r
223 \r
224         // ServiceProvider\r
225         TransactionLog* getTransactionLog() const {\r
226             if (m_tranLog)\r
227                 return m_tranLog;\r
228             throw ConfigurationException("No TransactionLog available.");\r
229         }\r
230 \r
231         StorageService* getStorageService(const char* id) const {\r
232             if (id) {\r
233                 map<string,StorageService*>::const_iterator i=m_storage.find(id);\r
234                 if (i!=m_storage.end())\r
235                     return i->second;\r
236             }\r
237             return NULL;\r
238         }\r
239 \r
240         ListenerService* getListenerService(bool required=true) const {\r
241             if (required && !m_listener)\r
242                 throw ConfigurationException("No ListenerService available.");\r
243             return m_listener;\r
244         }\r
245 \r
246         SessionCache* getSessionCache(bool required=true) const {\r
247             if (required && !m_sessionCache)\r
248                 throw ConfigurationException("No SessionCache available.");\r
249             return m_sessionCache;\r
250         }\r
251 \r
252         RequestMapper* getRequestMapper(bool required=true) const {\r
253             if (required && !m_impl->m_requestMapper)\r
254                 throw ConfigurationException("No RequestMapper available.");\r
255             return m_impl->m_requestMapper;\r
256         }\r
257 \r
258         const Application* getApplication(const char* applicationId) const {\r
259             map<string,Application*>::const_iterator i=m_impl->m_appmap.find(applicationId);\r
260             return (i!=m_impl->m_appmap.end()) ? i->second : NULL;\r
261         }\r
262 \r
263         const PropertySet* getPolicySettings(const char* id) const {\r
264             map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
265             if (i!=m_impl->m_policyMap.end())\r
266                 return i->second.first;\r
267             throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
268         }\r
269 \r
270         const vector<const SecurityPolicyRule*>& getPolicyRules(const char* id) const {\r
271             map<string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::const_iterator i = m_impl->m_policyMap.find(id);\r
272             if (i!=m_impl->m_policyMap.end())\r
273                 return i->second.second;\r
274             throw ConfigurationException("Security Policy ($1) not found, check <SecurityPolicies> element.", params(1,id));\r
275         }\r
276 \r
277     protected:\r
278         pair<bool,DOMElement*> load();\r
279 \r
280     private:\r
281         friend class XMLConfigImpl;\r
282         XMLConfigImpl* m_impl;\r
283         mutable ListenerService* m_listener;\r
284         mutable SessionCache* m_sessionCache;\r
285         mutable TransactionLog* m_tranLog;\r
286         mutable map<string,StorageService*> m_storage;\r
287     };\r
288 \r
289 #if defined (_MSC_VER)\r
290     #pragma warning( pop )\r
291 #endif\r
292 \r
293     static const XMLCh _Application[] =         UNICODE_LITERAL_11(A,p,p,l,i,c,a,t,i,o,n);\r
294     static const XMLCh Applications[] =         UNICODE_LITERAL_12(A,p,p,l,i,c,a,t,i,o,n,s);\r
295     static const XMLCh _ArtifactMap[] =         UNICODE_LITERAL_11(A,r,t,i,f,a,c,t,M,a,p);\r
296     static const XMLCh _AttributeExtractor[] =  UNICODE_LITERAL_18(A,t,t,r,i,b,u,t,e,E,x,t,r,a,c,t,o,r);\r
297     static const XMLCh _AttributeFilter[] =     UNICODE_LITERAL_15(A,t,t,r,i,b,u,t,e,F,i,l,t,e,r);\r
298     static const XMLCh _AttributeResolver[] =   UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);\r
299     static const XMLCh _CredentialResolver[] =  UNICODE_LITERAL_18(C,r,e,d,e,n,t,i,a,l,R,e,s,o,l,v,e,r);\r
300     static const XMLCh DefaultRelyingParty[] =  UNICODE_LITERAL_19(D,e,f,a,u,l,t,R,e,l,y,i,n,g,P,a,r,t,y);\r
301     static const XMLCh fatal[] =                UNICODE_LITERAL_5(f,a,t,a,l);\r
302     static const XMLCh _Handler[] =             UNICODE_LITERAL_7(H,a,n,d,l,e,r);\r
303     static const XMLCh _id[] =                  UNICODE_LITERAL_2(i,d);\r
304     static const XMLCh Implementation[] =       UNICODE_LITERAL_14(I,m,p,l,e,m,e,n,t,a,t,i,o,n);\r
305     static const XMLCh InProcess[] =            UNICODE_LITERAL_9(I,n,P,r,o,c,e,s,s);\r
306     static const XMLCh Library[] =              UNICODE_LITERAL_7(L,i,b,r,a,r,y);\r
307     static const XMLCh Listener[] =             UNICODE_LITERAL_8(L,i,s,t,e,n,e,r);\r
308     static const XMLCh logger[] =               UNICODE_LITERAL_6(l,o,g,g,e,r);\r
309     static const XMLCh MemoryListener[] =       UNICODE_LITERAL_14(M,e,m,o,r,y,L,i,s,t,e,n,e,r);\r
310     static const XMLCh _MetadataProvider[] =    UNICODE_LITERAL_16(M,e,t,a,d,a,t,a,P,r,o,v,i,d,e,r);\r
311     static const XMLCh OutOfProcess[] =         UNICODE_LITERAL_12(O,u,t,O,f,P,r,o,c,e,s,s);\r
312     static const XMLCh _path[] =                UNICODE_LITERAL_4(p,a,t,h);\r
313     static const XMLCh Policy[] =               UNICODE_LITERAL_6(P,o,l,i,c,y);\r
314     static const XMLCh RelyingParty[] =         UNICODE_LITERAL_12(R,e,l,y,i,n,g,P,a,r,t,y);\r
315     static const XMLCh _ReplayCache[] =         UNICODE_LITERAL_11(R,e,p,l,a,y,C,a,c,h,e);\r
316     static const XMLCh _RequestMapper[] =       UNICODE_LITERAL_13(R,e,q,u,e,s,t,M,a,p,p,e,r);\r
317     static const XMLCh Rule[] =                 UNICODE_LITERAL_4(R,u,l,e);\r
318     static const XMLCh SecurityPolicies[] =     UNICODE_LITERAL_16(S,e,c,u,r,i,t,y,P,o,l,i,c,i,e,s);\r
319     static const XMLCh _SessionCache[] =        UNICODE_LITERAL_12(S,e,s,s,i,o,n,C,a,c,h,e);\r
320     static const XMLCh _SessionInitiator[] =    UNICODE_LITERAL_16(S,e,s,s,i,o,n,I,n,i,t,i,a,t,o,r);\r
321     static const XMLCh _StorageService[] =      UNICODE_LITERAL_14(S,t,o,r,a,g,e,S,e,r,v,i,c,e);\r
322     static const XMLCh TCPListener[] =          UNICODE_LITERAL_11(T,C,P,L,i,s,t,e,n,e,r);\r
323     static const XMLCh _TrustEngine[] =         UNICODE_LITERAL_11(T,r,u,s,t,E,n,g,i,n,e);\r
324     static const XMLCh _type[] =                UNICODE_LITERAL_4(t,y,p,e);\r
325     static const XMLCh UnixListener[] =         UNICODE_LITERAL_12(U,n,i,x,L,i,s,t,e,n,e,r);\r
326 \r
327     class SHIBSP_DLLLOCAL PolicyNodeFilter : public DOMNodeFilter\r
328     {\r
329     public:\r
330         short acceptNode(const DOMNode* node) const {\r
331             if (XMLHelper::isNodeNamed(node,shibspconstants::SHIB2SPCONFIG_NS,Rule))\r
332                 return FILTER_REJECT;\r
333             return FILTER_ACCEPT;\r
334         }\r
335     };\r
336 };\r
337 \r
338 namespace shibsp {\r
339     ServiceProvider* XMLServiceProviderFactory(const DOMElement* const & e)\r
340     {\r
341         return new XMLConfig(e);\r
342     }\r
343 };\r
344 \r
345 XMLApplication::XMLApplication(\r
346     const ServiceProvider* sp,\r
347     const DOMElement* e,\r
348     const XMLApplication* base\r
349     ) : m_sp(sp), m_base(base), m_metadata(NULL), m_trust(NULL), m_attrExtractor(NULL), m_attrFilter(NULL), m_attrResolver(NULL),\r
350         m_credResolver(NULL), m_partyDefault(NULL), m_sessionInitDefault(NULL), m_acsDefault(NULL)\r
351 {\r
352 #ifdef _DEBUG\r
353     xmltooling::NDC ndc("XMLApplication");\r
354 #endif\r
355     Category& log=Category::getInstance(SHIBSP_LOGCAT".Application");\r
356 \r
357     try {\r
358         // First load any property sets.\r
359         load(e,log,this);\r
360         if (base)\r
361             setParent(base);\r
362 \r
363         SPConfig& conf=SPConfig::getConfig();\r
364         SAMLConfig& samlConf=SAMLConfig::getConfig();\r
365         XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();\r
366 \r
367         m_hash=getId();\r
368         m_hash+=getString("entityID").second;\r
369         m_hash=samlConf.hashSHA1(m_hash.c_str(), true);\r
370 \r
371         const PropertySet* sessions = getPropertySet("Sessions");\r
372 \r
373         // Process handlers.\r
374         Handler* handler=NULL;\r
375         bool hardACS=false, hardSessionInit=false;\r
376         const DOMElement* child = sessions ? XMLHelper::getFirstChildElement(sessions->getElement()) : NULL;\r
377         while (child) {\r
378             try {\r
379                 // A handler is based on the Binding property in conjunction with the element name.\r
380                 // If it's an ACS or SI, also handle index/id mappings and defaulting.\r
381                 if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,AssertionConsumerService::LOCAL_NAME)) {\r
382                     auto_ptr_char bindprop(child->getAttributeNS(NULL,EndpointType::BINDING_ATTRIB_NAME));\r
383                     if (!bindprop.get() || !*(bindprop.get())) {\r
384                         log.warn("md:AssertionConsumerService element has no Binding attribute, skipping it...");\r
385                         child = XMLHelper::getNextSiblingElement(child);\r
386                         continue;\r
387                     }\r
388                     handler=conf.AssertionConsumerServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
389                     // Map by binding (may be > 1 per binding, e.g. SAML 1.0 vs 1.1)\r
390 #ifdef HAVE_GOOD_STL\r
391                     m_acsBindingMap[handler->getXMLString("Binding").second].push_back(handler);\r
392 #else\r
393                     m_acsBindingMap[handler->getString("Binding").second].push_back(handler);\r
394 #endif\r
395                     m_acsIndexMap[handler->getUnsignedInt("index").second]=handler;\r
396                     \r
397                     if (!hardACS) {\r
398                         pair<bool,bool> defprop=handler->getBool("isDefault");\r
399                         if (defprop.first) {\r
400                             if (defprop.second) {\r
401                                 hardACS=true;\r
402                                 m_acsDefault=handler;\r
403                             }\r
404                         }\r
405                         else if (!m_acsDefault)\r
406                             m_acsDefault=handler;\r
407                     }\r
408                 }\r
409                 else if (XMLString::equals(child->getLocalName(),_SessionInitiator)) {\r
410                     auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
411                     if (!type.get() || !*(type.get())) {\r
412                         log.warn("SessionInitiator element has no type attribute, skipping it...");\r
413                         child = XMLHelper::getNextSiblingElement(child);\r
414                         continue;\r
415                     }\r
416                     SessionInitiator* sihandler=conf.SessionInitiatorManager.newPlugin(type.get(),make_pair(child, getId()));\r
417                     handler=sihandler;\r
418                     pair<bool,const char*> si_id=handler->getString("id");\r
419                     if (si_id.first && si_id.second)\r
420                         m_sessionInitMap[si_id.second]=sihandler;\r
421                     if (!hardSessionInit) {\r
422                         pair<bool,bool> defprop=handler->getBool("isDefault");\r
423                         if (defprop.first) {\r
424                             if (defprop.second) {\r
425                                 hardSessionInit=true;\r
426                                 m_sessionInitDefault=sihandler;\r
427                             }\r
428                         }\r
429                         else if (!m_sessionInitDefault)\r
430                             m_sessionInitDefault=sihandler;\r
431                     }\r
432                 }\r
433                 else if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,SingleLogoutService::LOCAL_NAME)) {\r
434                     auto_ptr_char bindprop(child->getAttributeNS(NULL,EndpointType::BINDING_ATTRIB_NAME));\r
435                     if (!bindprop.get() || !*(bindprop.get())) {\r
436                         log.warn("md:SingleLogoutService element has no Binding attribute, skipping it...");\r
437                         child = XMLHelper::getNextSiblingElement(child);\r
438                         continue;\r
439                     }\r
440                     handler=conf.SingleLogoutServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
441                 }\r
442                 else if (XMLHelper::isNodeNamed(child,samlconstants::SAML20MD_NS,ManageNameIDService::LOCAL_NAME)) {\r
443                     auto_ptr_char bindprop(child->getAttributeNS(NULL,EndpointType::BINDING_ATTRIB_NAME));\r
444                     if (!bindprop.get() || !*(bindprop.get())) {\r
445                         log.warn("md:ManageNameIDService element has no Binding attribute, skipping it...");\r
446                         child = XMLHelper::getNextSiblingElement(child);\r
447                         continue;\r
448                     }\r
449                     handler=conf.ManageNameIDServiceManager.newPlugin(bindprop.get(),make_pair(child, getId()));\r
450                 }\r
451                 else {\r
452                     auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
453                     if (!type.get() || !*(type.get())) {\r
454                         log.warn("Handler element has no type attribute, skipping it...");\r
455                         child = XMLHelper::getNextSiblingElement(child);\r
456                         continue;\r
457                     }\r
458                     handler=conf.HandlerManager.newPlugin(type.get(),make_pair(child, getId()));\r
459                 }\r
460 \r
461                 // Save off the objects after giving the property set to the handler for its use.\r
462                 m_handlers.push_back(handler);\r
463 \r
464                 // Insert into location map.\r
465                 pair<bool,const char*> location=handler->getString("Location");\r
466                 if (location.first && *location.second == '/')\r
467                     m_handlerMap[location.second]=handler;\r
468                 else if (location.first)\r
469                     m_handlerMap[string("/") + location.second]=handler;\r
470 \r
471             }\r
472             catch (exception& ex) {\r
473                 log.error("caught exception processing handler element: %s", ex.what());\r
474             }\r
475             \r
476             child = XMLHelper::getNextSiblingElement(child);\r
477         }\r
478 \r
479         DOMNodeList* nlist=e->getElementsByTagNameNS(samlconstants::SAML20_NS,Audience::LOCAL_NAME);\r
480         for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++)\r
481             if (nlist->item(i)->getParentNode()->isSameNode(e) && nlist->item(i)->hasChildNodes())\r
482                 m_audiences.push_back(nlist->item(i)->getFirstChild()->getNodeValue());\r
483 \r
484         // Always include our own entityID as an audience.\r
485         m_audiences.push_back(getXMLString("entityID").second);\r
486 \r
487         if (conf.isEnabled(SPConfig::Metadata)) {\r
488             child = XMLHelper::getFirstChildElement(e,_MetadataProvider);\r
489             if (child) {\r
490                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
491                 log.info("building MetadataProvider of type %s...",type.get());\r
492                 try {\r
493                     auto_ptr<MetadataProvider> mp(samlConf.MetadataProviderManager.newPlugin(type.get(),child));\r
494                     mp->init();\r
495                     m_metadata = mp.release();\r
496                 }\r
497                 catch (exception& ex) {\r
498                     log.crit("error building/initializing MetadataProvider: %s", ex.what());\r
499                 }\r
500             }\r
501         }\r
502 \r
503         if (conf.isEnabled(SPConfig::Trust)) {\r
504             child = XMLHelper::getFirstChildElement(e,_TrustEngine);\r
505             if (child) {\r
506                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
507                 log.info("building TrustEngine of type %s...",type.get());\r
508                 try {\r
509                     m_trust = xmlConf.TrustEngineManager.newPlugin(type.get(),child);\r
510                 }\r
511                 catch (exception& ex) {\r
512                     log.crit("error building TrustEngine: %s", ex.what());\r
513                 }\r
514             }\r
515         }\r
516 \r
517         if (conf.isEnabled(SPConfig::AttributeResolution)) {\r
518             child = XMLHelper::getFirstChildElement(e,_AttributeExtractor);\r
519             if (child) {\r
520                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
521                 log.info("building AttributeExtractor of type %s...",type.get());\r
522                 try {\r
523                     m_attrExtractor = conf.AttributeExtractorManager.newPlugin(type.get(),child);\r
524                 }\r
525                 catch (exception& ex) {\r
526                     log.crit("error building AttributeExtractor: %s", ex.what());\r
527                 }\r
528             }\r
529 \r
530             child = XMLHelper::getFirstChildElement(e,_AttributeFilter);\r
531             if (child) {\r
532                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
533                 log.info("building AttributeFilter of type %s...",type.get());\r
534                 try {\r
535                     m_attrFilter = conf.AttributeFilterManager.newPlugin(type.get(),child);\r
536                 }\r
537                 catch (exception& ex) {\r
538                     log.crit("error building AttributeFilter: %s", ex.what());\r
539                 }\r
540             }\r
541 \r
542             child = XMLHelper::getFirstChildElement(e,_AttributeResolver);\r
543             if (child) {\r
544                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
545                 log.info("building AttributeResolver of type %s...",type.get());\r
546                 try {\r
547                     m_attrResolver = conf.AttributeResolverManager.newPlugin(type.get(),child);\r
548                 }\r
549                 catch (exception& ex) {\r
550                     log.crit("error building AttributeResolver: %s", ex.what());\r
551                 }\r
552             }\r
553         }\r
554 \r
555         if (conf.isEnabled(SPConfig::Credentials)) {\r
556             child = XMLHelper::getFirstChildElement(e,_CredentialResolver);\r
557             if (child) {\r
558                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
559                 log.info("building CredentialResolver of type %s...",type.get());\r
560                 try {\r
561                     m_credResolver = xmlConf.CredentialResolverManager.newPlugin(type.get(),child);\r
562                 }\r
563                 catch (exception& ex) {\r
564                     log.crit("error building CredentialResolver: %s", ex.what());\r
565                 }\r
566             }\r
567         }\r
568 \r
569 \r
570         // Finally, load relying parties.\r
571         child = XMLHelper::getFirstChildElement(e,DefaultRelyingParty);\r
572         if (child) {\r
573             m_partyDefault=new DOMPropertySet();\r
574             m_partyDefault->load(child,log,this);\r
575             child = XMLHelper::getFirstChildElement(child,RelyingParty);\r
576             while (child) {\r
577                 auto_ptr<DOMPropertySet> rp(new DOMPropertySet());\r
578                 rp->load(child,log,this);\r
579                 m_partyMap[child->getAttributeNS(NULL,saml2::Attribute::NAME_ATTRIB_NAME)]=rp.release();\r
580                 child = XMLHelper::getNextSiblingElement(child,RelyingParty);\r
581             }\r
582         }\r
583         \r
584         if (conf.isEnabled(SPConfig::OutOfProcess)) {\r
585             // Really finally, build local browser profile and binding objects.\r
586             // TODO: may need some bits here...\r
587         }\r
588     }\r
589     catch (exception&) {\r
590         cleanup();\r
591         throw;\r
592     }\r
593 #ifndef _DEBUG\r
594     catch (...) {\r
595         cleanup();\r
596         throw;\r
597     }\r
598 #endif\r
599 }\r
600 \r
601 void XMLApplication::cleanup()\r
602 {\r
603     delete m_partyDefault;\r
604 #ifdef HAVE_GOOD_STL\r
605     for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<xstring,PropertySet>());\r
606 #else\r
607     for_each(m_partyMap.begin(),m_partyMap.end(),cleanup_pair<const XMLCh*,PropertySet>());\r
608 #endif\r
609     for_each(m_handlers.begin(),m_handlers.end(),xmltooling::cleanup<Handler>());\r
610     delete m_credResolver;\r
611     delete m_attrResolver;\r
612     delete m_attrFilter;\r
613     delete m_attrExtractor;\r
614     delete m_trust;\r
615     delete m_metadata;\r
616 }\r
617 \r
618 short XMLApplication::acceptNode(const DOMNode* node) const\r
619 {\r
620     if (XMLHelper::isNodeNamed(node,samlconstants::SAML20_NS,saml2::Attribute::LOCAL_NAME))\r
621         return FILTER_REJECT;\r
622     else if (XMLHelper::isNodeNamed(node,samlconstants::SAML20_NS,Audience::LOCAL_NAME))\r
623         return FILTER_REJECT;\r
624     const XMLCh* name=node->getLocalName();\r
625     if (XMLString::equals(name,_Application) ||\r
626         XMLString::equals(name,AssertionConsumerService::LOCAL_NAME) ||\r
627         XMLString::equals(name,SingleLogoutService::LOCAL_NAME) ||\r
628         XMLString::equals(name,ManageNameIDService::LOCAL_NAME) ||\r
629         XMLString::equals(name,_SessionInitiator) ||\r
630         XMLString::equals(name,DefaultRelyingParty) ||\r
631         XMLString::equals(name,RelyingParty) ||\r
632         XMLString::equals(name,_MetadataProvider) ||\r
633         XMLString::equals(name,_TrustEngine) ||\r
634         XMLString::equals(name,_CredentialResolver) ||\r
635         XMLString::equals(name,_AttributeFilter) ||\r
636         XMLString::equals(name,_AttributeExtractor) ||\r
637         XMLString::equals(name,_AttributeResolver))\r
638         return FILTER_REJECT;\r
639 \r
640     return FILTER_ACCEPT;\r
641 }\r
642 \r
643 const PropertySet* XMLApplication::getRelyingParty(const EntityDescriptor* provider) const\r
644 {\r
645     if (!m_partyDefault && m_base)\r
646         return m_base->getRelyingParty(provider);\r
647     else if (!provider)\r
648         return m_partyDefault;\r
649         \r
650 #ifdef HAVE_GOOD_STL\r
651     map<xstring,PropertySet*>::const_iterator i=m_partyMap.find(provider->getEntityID());\r
652     if (i!=m_partyMap.end())\r
653         return i->second;\r
654     const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());\r
655     while (group) {\r
656         if (group->getName()) {\r
657             i=m_partyMap.find(group->getName());\r
658             if (i!=m_partyMap.end())\r
659                 return i->second;\r
660         }\r
661         group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());\r
662     }\r
663 #else\r
664     map<const XMLCh*,PropertySet*>::const_iterator i=m_partyMap.begin();\r
665     for (; i!=m_partyMap.end(); i++) {\r
666         if (XMLString::equals(i->first,provider->getId()))\r
667             return i->second;\r
668         const EntitiesDescriptor* group=dynamic_cast<const EntitiesDescriptor*>(provider->getParent());\r
669         while (group) {\r
670             if (XMLString::equals(i->first,group->getName()))\r
671                 return i->second;\r
672             group=dynamic_cast<const EntitiesDescriptor*>(group->getParent());\r
673         }\r
674     }\r
675 #endif\r
676     return m_partyDefault;\r
677 }\r
678 \r
679 const SessionInitiator* XMLApplication::getDefaultSessionInitiator() const\r
680 {\r
681     if (m_sessionInitDefault) return m_sessionInitDefault;\r
682     return m_base ? m_base->getDefaultSessionInitiator() : NULL;\r
683 }\r
684 \r
685 const SessionInitiator* XMLApplication::getSessionInitiatorById(const char* id) const\r
686 {\r
687     map<string,const SessionInitiator*>::const_iterator i=m_sessionInitMap.find(id);\r
688     if (i!=m_sessionInitMap.end()) return i->second;\r
689     return m_base ? m_base->getSessionInitiatorById(id) : NULL;\r
690 }\r
691 \r
692 const Handler* XMLApplication::getDefaultAssertionConsumerService() const\r
693 {\r
694     if (m_acsDefault) return m_acsDefault;\r
695     return m_base ? m_base->getDefaultAssertionConsumerService() : NULL;\r
696 }\r
697 \r
698 const Handler* XMLApplication::getAssertionConsumerServiceByIndex(unsigned short index) const\r
699 {\r
700     map<unsigned int,const Handler*>::const_iterator i=m_acsIndexMap.find(index);\r
701     if (i!=m_acsIndexMap.end()) return i->second;\r
702     return m_base ? m_base->getAssertionConsumerServiceByIndex(index) : NULL;\r
703 }\r
704 \r
705 const vector<const Handler*>& XMLApplication::getAssertionConsumerServicesByBinding(const XMLCh* binding) const\r
706 {\r
707 #ifdef HAVE_GOOD_STL\r
708     ACSBindingMap::const_iterator i=m_acsBindingMap.find(binding);\r
709 #else\r
710     auto_ptr_char temp(binding);\r
711     ACSBindingMap::const_iterator i=m_acsBindingMap.find(temp.get());\r
712 #endif\r
713     if (i!=m_acsBindingMap.end())\r
714         return i->second;\r
715     return m_base ? m_base->getAssertionConsumerServicesByBinding(binding) : g_noHandlers;\r
716 }\r
717 \r
718 const Handler* XMLApplication::getHandler(const char* path) const\r
719 {\r
720     string wrap(path);\r
721     map<string,const Handler*>::const_iterator i=m_handlerMap.find(wrap.substr(0,wrap.find('?')));\r
722     if (i!=m_handlerMap.end())\r
723         return i->second;\r
724     return m_base ? m_base->getHandler(path) : NULL;\r
725 }\r
726 \r
727 short XMLConfigImpl::acceptNode(const DOMNode* node) const\r
728 {\r
729     if (!XMLString::equals(node->getNamespaceURI(),shibspconstants::SHIB2SPCONFIG_NS))\r
730         return FILTER_ACCEPT;\r
731     const XMLCh* name=node->getLocalName();\r
732     if (XMLString::equals(name,Applications) ||\r
733         XMLString::equals(name,_ArtifactMap) ||\r
734         XMLString::equals(name,Extensions::LOCAL_NAME) ||\r
735         XMLString::equals(name,Implementation) ||\r
736         XMLString::equals(name,Listener) ||\r
737         XMLString::equals(name,MemoryListener) ||\r
738         XMLString::equals(name,Policy) ||\r
739         XMLString::equals(name,_RequestMapper) ||\r
740         XMLString::equals(name,_ReplayCache) ||\r
741         XMLString::equals(name,_SessionCache) ||\r
742         XMLString::equals(name,_StorageService) ||\r
743         XMLString::equals(name,TCPListener) ||\r
744         XMLString::equals(name,UnixListener))\r
745         return FILTER_REJECT;\r
746 \r
747     return FILTER_ACCEPT;\r
748 }\r
749 \r
750 void XMLConfigImpl::doExtensions(const DOMElement* e, const char* label, Category& log)\r
751 {\r
752     const DOMElement* exts=XMLHelper::getFirstChildElement(e,Extensions::LOCAL_NAME);\r
753     if (exts) {\r
754         exts=XMLHelper::getFirstChildElement(exts,Library);\r
755         while (exts) {\r
756             auto_ptr_char path(exts->getAttributeNS(NULL,_path));\r
757             try {\r
758                 if (path.get()) {\r
759                     XMLToolingConfig::getConfig().load_library(path.get(),(void*)exts);\r
760                     log.debug("loaded %s extension library (%s)", label, path.get());\r
761                 }\r
762             }\r
763             catch (exception& e) {\r
764                 const XMLCh* fatal=exts->getAttributeNS(NULL,fatal);\r
765                 if (fatal && (*fatal==chLatin_t || *fatal==chDigit_1)) {\r
766                     log.fatal("unable to load mandatory %s extension library %s: %s", label, path.get(), e.what());\r
767                     throw;\r
768                 }\r
769                 else {\r
770                     log.crit("unable to load optional %s extension library %s: %s", label, path.get(), e.what());\r
771                 }\r
772             }\r
773             exts=XMLHelper::getNextSiblingElement(exts,Library);\r
774         }\r
775     }\r
776 }\r
777 \r
778 XMLConfigImpl::XMLConfigImpl(const DOMElement* e, bool first, const XMLConfig* outer, Category& log)\r
779     : m_requestMapper(NULL), m_outer(outer), m_document(NULL)\r
780 {\r
781 #ifdef _DEBUG\r
782     xmltooling::NDC ndc("XMLConfigImpl");\r
783 #endif\r
784 \r
785     try {\r
786         SPConfig& conf=SPConfig::getConfig();\r
787         SAMLConfig& samlConf=SAMLConfig::getConfig();\r
788         XMLToolingConfig& xmlConf=XMLToolingConfig::getConfig();\r
789         const DOMElement* SHAR=XMLHelper::getFirstChildElement(e,OutOfProcess);\r
790         const DOMElement* SHIRE=XMLHelper::getFirstChildElement(e,InProcess);\r
791 \r
792         // Initialize log4cpp manually in order to redirect log messages as soon as possible.\r
793         if (conf.isEnabled(SPConfig::Logging)) {\r
794             const XMLCh* logconf=NULL;\r
795             if (conf.isEnabled(SPConfig::OutOfProcess))\r
796                 logconf=SHAR->getAttributeNS(NULL,logger);\r
797             else if (conf.isEnabled(SPConfig::InProcess))\r
798                 logconf=SHIRE->getAttributeNS(NULL,logger);\r
799             if (!logconf || !*logconf)\r
800                 logconf=e->getAttributeNS(NULL,logger);\r
801             if (logconf && *logconf) {\r
802                 auto_ptr_char logpath(logconf);\r
803                 log.debug("loading new logging configuration from (%s), check log destination for status of configuration",logpath.get());\r
804                 XMLToolingConfig::getConfig().log_config(logpath.get());\r
805             }\r
806             \r
807             if (first)\r
808                 m_outer->m_tranLog = new TransactionLog();\r
809         }\r
810         \r
811         // First load any property sets.\r
812         load(e,log,this);\r
813 \r
814         const DOMElement* child;\r
815         string plugtype;\r
816 \r
817         // Much of the processing can only occur on the first instantiation.\r
818         if (first) {\r
819             // Set clock skew.\r
820             pair<bool,unsigned int> skew=getUnsignedInt("clockSkew");\r
821             if (skew.first)\r
822                 xmlConf.clock_skew_secs=skew.second;\r
823 \r
824             // Extensions\r
825             doExtensions(e, "global", log);\r
826             if (conf.isEnabled(SPConfig::OutOfProcess))\r
827                 doExtensions(SHAR, "out of process", log);\r
828 \r
829             if (conf.isEnabled(SPConfig::InProcess))\r
830                 doExtensions(SHIRE, "in process", log);\r
831             \r
832             // Instantiate the ListenerService and SessionCache objects.\r
833             if (conf.isEnabled(SPConfig::Listener)) {\r
834                 child=XMLHelper::getFirstChildElement(SHAR,UnixListener);\r
835                 if (child)\r
836                     plugtype=UNIX_LISTENER_SERVICE;\r
837                 else {\r
838                     child=XMLHelper::getFirstChildElement(SHAR,TCPListener);\r
839                     if (child)\r
840                         plugtype=TCP_LISTENER_SERVICE;\r
841                     else {\r
842                         child=XMLHelper::getFirstChildElement(SHAR,MemoryListener);\r
843                         if (child)\r
844                             plugtype=MEMORY_LISTENER_SERVICE;\r
845                         else {\r
846                             child=XMLHelper::getFirstChildElement(SHAR,Listener);\r
847                             if (child) {\r
848                                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
849                                 if (type.get())\r
850                                     plugtype=type.get();\r
851                             }\r
852                         }\r
853                     }\r
854                 }\r
855                 if (child) {\r
856                     log.info("building ListenerService of type %s...", plugtype.c_str());\r
857                     m_outer->m_listener = conf.ListenerServiceManager.newPlugin(plugtype.c_str(),child);\r
858                 }\r
859                 else {\r
860                     log.fatal("can't build ListenerService, missing conf:Listener element?");\r
861                     throw ConfigurationException("Can't build ListenerService, missing conf:Listener element?");\r
862                 }\r
863             }\r
864 \r
865             if (conf.isEnabled(SPConfig::Caching)) {\r
866                 if (conf.isEnabled(SPConfig::OutOfProcess)) {\r
867                     // First build any StorageServices.\r
868                     string inmemID;\r
869                     child=XMLHelper::getFirstChildElement(SHAR,_StorageService);\r
870                     while (child) {\r
871                         auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
872                         auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
873                         try {\r
874                             log.info("building StorageService (%s) of type %s...", id.get(), type.get());\r
875                             m_outer->m_storage[id.get()] = xmlConf.StorageServiceManager.newPlugin(type.get(),child);\r
876                             if (!strcmp(type.get(),MEMORY_STORAGE_SERVICE))\r
877                                 inmemID = id.get();\r
878                         }\r
879                         catch (exception& ex) {\r
880                             log.crit("failed to instantiate StorageService (%s): %s", id.get(), ex.what());\r
881                         }\r
882                         child=XMLHelper::getNextSiblingElement(child,_StorageService);\r
883                     }\r
884                 \r
885                     child=XMLHelper::getFirstChildElement(SHAR,_SessionCache);\r
886                     if (child) {\r
887                         auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
888                         log.info("building SessionCache of type %s...",type.get());\r
889                         m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(type.get(),child);\r
890                     }\r
891                     else {\r
892                         log.warn("SessionCache unspecified, building SessionCache of type %s...",STORAGESERVICE_SESSION_CACHE);\r
893                         if (inmemID.empty()) {\r
894                             inmemID = "memory";\r
895                             log.info("no StorageServices configured, providing in-memory version for session cache");\r
896                             m_outer->m_storage[inmemID] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE,NULL);\r
897                         }\r
898                         child = e->getOwnerDocument()->createElementNS(NULL,_SessionCache);\r
899                         auto_ptr_XMLCh ssid(inmemID.c_str());\r
900                         const_cast<DOMElement*>(child)->setAttributeNS(NULL,_StorageService,ssid.get());\r
901                         m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(STORAGESERVICE_SESSION_CACHE,child);\r
902                     }\r
903 \r
904                     // Replay cache.\r
905                     StorageService* replaySS=NULL;\r
906                     child=XMLHelper::getFirstChildElement(SHAR,_ReplayCache);\r
907                     if (child) {\r
908                         auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));\r
909                         if (ssid.get() && *ssid.get()) {\r
910                             if (m_outer->m_storage.count(ssid.get()))\r
911                                 replaySS = m_outer->m_storage[ssid.get()];\r
912                             if (replaySS)\r
913                                 log.info("building ReplayCache on top of StorageService (%s)...", ssid.get());\r
914                             else\r
915                                 log.crit("unable to locate StorageService (%s) in configuration", ssid.get());\r
916                         }\r
917                     }\r
918                     if (!replaySS) {\r
919                         log.info("building ReplayCache using in-memory StorageService...");\r
920                         if (inmemID.empty()) {\r
921                             inmemID = "memory";\r
922                             log.info("no StorageServices configured, providing in-memory version for legacy config");\r
923                             m_outer->m_storage[inmemID] = xmlConf.StorageServiceManager.newPlugin(MEMORY_STORAGE_SERVICE,NULL);\r
924                         }\r
925                         replaySS = m_outer->m_storage[inmemID];\r
926                     }\r
927                     xmlConf.setReplayCache(new ReplayCache(replaySS));\r
928                     \r
929                     // ArtifactMap\r
930                     child=XMLHelper::getFirstChildElement(SHAR,_ArtifactMap);\r
931                     if (child) {\r
932                         auto_ptr_char ssid(child->getAttributeNS(NULL,_StorageService));\r
933                         if (ssid.get() && *ssid.get() && m_outer->m_storage.count(ssid.get())) {\r
934                             log.info("building ArtifactMap on top of StorageService (%s)...", ssid.get());\r
935                             samlConf.setArtifactMap(new ArtifactMap(child, m_outer->m_storage[ssid.get()]));\r
936                         }\r
937                     }\r
938                     if (samlConf.getArtifactMap()==NULL) {\r
939                         log.info("building in-memory ArtifactMap...");\r
940                         samlConf.setArtifactMap(new ArtifactMap(child));\r
941                     }\r
942                 }\r
943                 else {\r
944                     child=XMLHelper::getFirstChildElement(SHIRE,_SessionCache);\r
945                     if (child) {\r
946                         auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
947                         log.info("building SessionCache of type %s...",type.get());\r
948                         m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(type.get(),child);\r
949                     }\r
950                     else {\r
951                         log.warn("SessionCache unspecified, building SessionCache of type %s...",REMOTED_SESSION_CACHE);\r
952                         m_outer->m_sessionCache=conf.SessionCacheManager.newPlugin(REMOTED_SESSION_CACHE,child);\r
953                     }\r
954                 }\r
955             }\r
956         } // end of first-time-only stuff\r
957         \r
958         // Back to the fully dynamic stuff...next up is the RequestMapper.\r
959         if (conf.isEnabled(SPConfig::RequestMapping)) {\r
960             child=XMLHelper::getFirstChildElement(SHIRE,_RequestMapper);\r
961             if (child) {\r
962                 auto_ptr_char type(child->getAttributeNS(NULL,_type));\r
963                 log.info("building RequestMapper of type %s...",type.get());\r
964                 m_requestMapper=conf.RequestMapperManager.newPlugin(type.get(),child);\r
965             }\r
966         }\r
967         \r
968         // Load security policies.\r
969         child = XMLHelper::getLastChildElement(e,SecurityPolicies);\r
970         if (child) {\r
971             PolicyNodeFilter filter;\r
972             child = XMLHelper::getFirstChildElement(child,Policy);\r
973             while (child) {\r
974                 auto_ptr_char id(child->getAttributeNS(NULL,_id));\r
975                 pair< PropertySet*,vector<const SecurityPolicyRule*> >& rules = m_policyMap[id.get()];\r
976                 rules.first = NULL;\r
977                 auto_ptr<DOMPropertySet> settings(new DOMPropertySet());\r
978                 settings->load(child, log, &filter);\r
979                 rules.first = settings.release();\r
980                 const DOMElement* rule = XMLHelper::getFirstChildElement(child,Rule);\r
981                 while (rule) {\r
982                     auto_ptr_char type(rule->getAttributeNS(NULL,_type));\r
983                     try {\r
984                         rules.second.push_back(samlConf.SecurityPolicyRuleManager.newPlugin(type.get(),rule));\r
985                     }\r
986                     catch (exception& ex) {\r
987                         log.crit("error instantiating policy rule (%s) in policy (%s): %s", type.get(), id.get(), ex.what());\r
988                     }\r
989                     rule = XMLHelper::getNextSiblingElement(rule,Rule);\r
990                 }\r
991                 child = XMLHelper::getNextSiblingElement(child,Policy);\r
992             }\r
993         }\r
994 \r
995         // Load the default application. This actually has a fixed ID of "default". ;-)\r
996         child=XMLHelper::getLastChildElement(e,Applications);\r
997         if (!child) {\r
998             log.fatal("can't build default Application object, missing conf:Applications element?");\r
999             throw ConfigurationException("can't build default Application object, missing conf:Applications element?");\r
1000         }\r
1001         XMLApplication* defapp=new XMLApplication(m_outer,child);\r
1002         m_appmap[defapp->getId()]=defapp;\r
1003         \r
1004         // Load any overrides.\r
1005         child = XMLHelper::getFirstChildElement(child,_Application);\r
1006         while (child) {\r
1007             auto_ptr<XMLApplication> iapp(new XMLApplication(m_outer,child,defapp));\r
1008             if (m_appmap.count(iapp->getId()))\r
1009                 log.crit("found conf:Application element with duplicate id attribute (%s), skipping it", iapp->getId());\r
1010             else\r
1011                 m_appmap[iapp->getId()]=iapp.release();\r
1012 \r
1013             child = XMLHelper::getNextSiblingElement(child,_Application);\r
1014         }\r
1015     }\r
1016     catch (exception&) {\r
1017         this->~XMLConfigImpl();\r
1018         throw;\r
1019     }\r
1020 #ifndef _DEBUG\r
1021     catch (...) {\r
1022         this->~XMLConfigImpl();\r
1023         throw;\r
1024     }\r
1025 #endif\r
1026 }\r
1027 \r
1028 XMLConfigImpl::~XMLConfigImpl()\r
1029 {\r
1030     for_each(m_appmap.begin(),m_appmap.end(),cleanup_pair<string,Application>());\r
1031     for (map< string,pair<PropertySet*,vector<const SecurityPolicyRule*> > >::iterator i=m_policyMap.begin(); i!=m_policyMap.end(); ++i) {\r
1032         delete i->second.first;\r
1033         for_each(i->second.second.begin(), i->second.second.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
1034     }\r
1035     delete m_requestMapper;\r
1036     if (m_document)\r
1037         m_document->release();\r
1038 }\r
1039 \r
1040 pair<bool,DOMElement*> XMLConfig::load()\r
1041 {\r
1042     // Load from source using base class.\r
1043     pair<bool,DOMElement*> raw = ReloadableXMLFile::load();\r
1044     \r
1045     // If we own it, wrap it.\r
1046     XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);\r
1047 \r
1048     XMLConfigImpl* impl = new XMLConfigImpl(raw.second,(m_impl==NULL),this,m_log);\r
1049     \r
1050     // If we held the document, transfer it to the impl. If we didn't, it's a no-op.\r
1051     impl->setDocument(docjanitor.release());\r
1052 \r
1053     delete m_impl;\r
1054     m_impl = impl;\r
1055 \r
1056     return make_pair(false,(DOMElement*)NULL);\r
1057 }\r