Use for_each alg for cleanup.
[shibboleth/sp.git] / xmlproviders / XMLMetadata.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
18 /* XMLMetadata.cpp - a metadata implementation that uses an XML-based registry
19
20    Scott Cantor
21    9/27/02
22
23    $History:$
24 */
25
26 #include "internal.h"
27
28 #include <algorithm>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31
32 #include <log4cpp/Category.hh>
33 #include <xercesc/util/XMLChar.hpp>
34 #include <xsec/dsig/DSIGTransformC14n.hpp>
35 #include <xsec/dsig/DSIGReference.hpp>
36 #include <xsec/dsig/DSIGTransformList.hpp>
37 #include <xsec/enc/XSECCryptoException.hpp>
38 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
39 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
40 #include <xsec/framework/XSECException.hpp>
41 #include <xsec/framework/XSECProvider.hpp>
42
43 using namespace xmlproviders;
44 using namespace shibboleth;
45 using namespace saml;
46 using namespace log4cpp;
47 using namespace std;
48
49 namespace {
50
51     class XMLMetadata;
52     class XMLMetadataImpl : public ReloadableXMLFileImpl
53     {
54     public:
55         class ContactPerson : public IContactPerson
56         {
57         public:
58             ContactPerson(const DOMElement* e);
59             ~ContactPerson() {}
60         
61             ContactType getType() const { return m_type; }
62             const char* getCompany() const { return m_company.get(); }
63             const char* getGivenName() const { return m_givenName.get(); }
64             const char* getSurName() const { return m_surName.get(); }
65             Iterator<string> getEmailAddresses() const { return m_emails; }
66             Iterator<string> getTelephoneNumbers() const { return m_phones; }
67             const DOMElement* getElement() const { return m_root; }
68         
69         private:
70             const DOMElement* m_root;
71             ContactType m_type;
72             auto_ptr<char> m_givenName,m_surName,m_company;
73             vector<string> m_emails,m_phones;
74         };
75         
76         class Organization : public IOrganization
77         {
78         public:
79             Organization(const DOMElement* e);
80             ~Organization() {}
81             
82             const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
83             const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
84             const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
85             const DOMElement* getElement() const { return m_root; }
86         
87         private:
88             const char* forLang(const map<string,string>& m, const char* lang) const {
89                 map<string,string>::const_iterator i=m.find(lang);
90                 return (i==m.end()) ? NULL : i->second.c_str();
91             }
92             const DOMElement* m_root;
93             map<string,string> m_names,m_displays,m_urls;
94         };
95
96         class EntityDescriptor;
97         
98         class EncryptionMethod : public XENCEncryptionMethod
99         {
100         public:
101             EncryptionMethod(const DOMElement* e);
102             ~EncryptionMethod() {}
103             
104             const XMLCh * getAlgorithm(void) const { return m_alg; }
105             const XMLCh * getDigestMethod(void) const { return m_digest; }
106             const XMLCh * getOAEPparams(void) const { return m_params; }
107             int getKeySize(void) const { return m_size; }
108             DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
109             void setDigestMethod(const XMLCh * method) {throw exception();}
110             void setOAEPparams(const XMLCh * params) {throw exception();}
111             void setKeySize(int size) {throw exception();}
112         
113         private:
114             const DOMElement* m_root;
115             const XMLCh* m_alg;
116             const XMLCh* m_digest;
117             const XMLCh* m_params;
118             int m_size;
119         };
120         
121         class KeyDescriptor : public IKeyDescriptor
122         {
123         public:
124             KeyDescriptor(const DOMElement* e);
125             ~KeyDescriptor();
126             
127             KeyUse getUse() const { return m_use; }
128             DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
129             saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
130             const DOMElement* getElement() const { return m_root; }
131         
132         private:
133             const DOMElement* m_root;
134             KeyUse m_use;
135             mutable DSIGKeyInfoList* m_klist;
136             vector<const XENCEncryptionMethod*> m_methods;
137         };
138         
139         class KeyAuthority : public IKeyAuthority
140         {
141         public:
142             KeyAuthority(const DOMElement* e);
143             ~KeyAuthority();
144             
145             int getVerifyDepth() const { return m_depth; }
146             Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
147         
148         private:
149             int m_depth;
150             vector<DSIGKeyInfoList*> m_klists;
151         };
152         
153         class Role : public virtual IRoleDescriptor
154         {
155         public:
156             Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
157             ~Role();
158             
159             // External contract
160             const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
161             Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
162             bool hasSupport(const XMLCh* protocol) const;
163             const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
164             bool isValid() const {return time(NULL) < m_validUntil;}
165             Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
166             const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
167             Iterator<const IContactPerson*> getContactPersons() const
168                 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
169             const DOMElement* getElement() const {return m_root;}
170         
171         protected:
172             vector<const XMLCh*> m_protocolEnum;
173             vector<const IKeyDescriptor*> m_keys;
174
175         private:
176             const EntityDescriptor* m_provider;
177             const DOMElement* m_root;
178             XMLCh* m_protocolEnumCopy;
179             char* m_errorURL;
180             Organization* m_org;
181             vector<const IContactPerson*> m_contacts;
182             time_t m_validUntil;
183         };
184         
185         class Endpoint : public virtual IEndpoint
186         {
187         public:
188             Endpoint(const DOMElement* e) : m_root(e),
189                 m_binding(e->getAttributeNS(NULL,L(Binding))),
190                 m_location(e->getAttributeNS(NULL,L(Location))),
191                 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
192             Endpoint(const XMLCh* binding, const XMLCh* loc)
193                 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
194             ~Endpoint() {}
195             
196             const XMLCh* getBinding() const { return m_binding; }
197             const XMLCh* getLocation() const { return m_location; }
198             const XMLCh* getResponseLocation() const { return m_resploc; }
199             const DOMElement* getElement() const { return m_root; }
200         
201         private:
202             const DOMElement* m_root;
203             const XMLCh* m_binding;
204             const XMLCh* m_location;
205             const XMLCh* m_resploc;
206         };
207         
208         class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
209         {
210         public:
211             IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
212             unsigned short getIndex() const {return m_index;}
213             
214         private:
215             unsigned short m_index;
216         };
217         
218         class EndpointManager : public IEndpointManager
219         {
220         public:
221             EndpointManager() : m_soft(NULL), m_hard(NULL) {}
222             ~EndpointManager() {
223                 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
224                     delete const_cast<IEndpoint*>(*i);
225             }
226             saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
227             const IEndpoint* getDefaultEndpoint() const {
228                 if (m_hard) return m_hard;
229                 if (m_soft) return m_soft;
230                 if (!m_endpoints.empty()) return *(m_endpoints.begin());
231                 return NULL;
232             }
233             const IEndpoint* getEndpointByIndex(unsigned short index) const {
234                 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
235                     const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
236                     if (temp && index==temp->getIndex())
237                         return temp;
238                 }
239                 return NULL;
240             }
241             const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
242                 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
243                     if (!XMLString::compareString(binding,(*i)->getBinding()))
244                         return *i;
245                 return NULL;
246             }
247             void add(IEndpoint* e) {
248                 m_endpoints.push_back(e);
249                 if (!m_hard && e->getElement()) {
250                     const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
251                     if (v && (*v==chDigit_1 || *v==chLatin_t))  // explicit default
252                         m_hard=e;
253                     else if ((!v || !*v) && !m_soft)            // implicit default
254                         m_soft=e;
255                 }
256                 else if (!m_hard && !m_soft) {
257                     // No default yet, so this one qualifies as an implicit.
258                     m_soft=e;
259                 }
260             }
261             
262         private:
263             vector<const IEndpoint*> m_endpoints;
264             const IEndpoint* m_soft;    // Soft default (not explicit)
265             const IEndpoint* m_hard;    // Hard default (explicit)
266         };
267         
268         class SSORole : public Role, public virtual ISSODescriptor
269         {
270         public:
271             SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
272             ~SSORole() {}
273             const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
274             const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
275             const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
276             saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
277             
278         private:
279             EndpointManager m_artifact,m_logout,m_nameid;
280             vector<const XMLCh*> m_formats;
281         };
282
283         class ScopedRole : public virtual IScopedRoleDescriptor
284         {
285         public:
286             ScopedRole(const DOMElement* e);
287             saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
288
289         private:
290             vector<pair<const XMLCh*,bool> > m_scopes;
291         };
292         
293         class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
294         {
295         public:
296             IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
297             ~IDPRole();
298             bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
299             const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
300             const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
301             const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
302             saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
303             saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
304         
305         private:
306             EndpointManager m_sso,m_mapping,m_idreq;
307             vector<const XMLCh*> m_attrprofs;
308             vector<const SAMLAttribute*> m_attrs;
309             bool m_wantAuthnRequestsSigned;
310             const XMLCh* m_sourceId;
311             friend class EntityDescriptor;
312         };
313
314         class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
315         {
316         public:
317             AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
318             ~AARole();
319             const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
320             const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
321             saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
322             saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
323             saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
324         
325         private:
326             EndpointManager m_query,m_idreq;
327             vector<const XMLCh*> m_formats,m_attrprofs;
328             vector<const SAMLAttribute*> m_attrs;
329         };
330     
331         class EntityDescriptor : public IExtendedEntityDescriptor
332         {
333         public:
334             EntityDescriptor(
335                 const DOMElement* e,
336                 XMLMetadataImpl* wrapper,
337                 time_t validUntil=LONG_MAX,
338                 const IEntitiesDescriptor* parent=NULL
339                 );
340             ~EntityDescriptor();
341         
342             // External contract
343             const XMLCh* getId() const {return m_id;}
344             bool isValid() const {return time(NULL) < m_validUntil;}
345             Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
346             const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
347             const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
348             const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
349             const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
350             const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
351             const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
352             const IOrganization* getOrganization() const {return m_org;}
353             Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
354             Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
355             const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
356             Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
357             const DOMElement* getElement() const {return m_root;}
358
359             // Used internally
360             const char* getErrorURL() const {return m_errorURL.get();}
361             time_t getValidUntil() const {return m_validUntil;}
362         private:
363             const DOMElement* m_root;
364             const IEntitiesDescriptor* m_parent;
365             const XMLCh* m_id;
366             auto_ptr<char> m_errorURL;
367             IOrganization* m_org;
368             vector<const IContactPerson*> m_contacts;
369             vector<const IRoleDescriptor*> m_roles;
370             vector<pair<const XMLCh*,const XMLCh*> > m_locs;
371             vector<const IKeyAuthority*> m_keyauths;
372             time_t m_validUntil;
373         };
374
375         class EntitiesDescriptor : public IExtendedEntitiesDescriptor
376         {
377         public:
378             EntitiesDescriptor(
379                 const DOMElement* e,
380                 XMLMetadataImpl* wrapper,
381                 time_t validUntil=LONG_MAX,
382                 const IEntitiesDescriptor* parent=NULL
383                 );
384             ~EntitiesDescriptor();
385             
386             const XMLCh* getName() const {return m_name;}
387             bool isValid() const {return time(NULL) < m_validUntil;}
388             const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
389             Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
390             Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
391             Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
392             const DOMElement* getElement() const {return m_root;}
393         
394             // Used internally
395             time_t getValidUntil() const {return m_validUntil;}
396         private:
397             const DOMElement* m_root;
398             const IEntitiesDescriptor* m_parent;
399             const XMLCh* m_name;
400             vector<const IEntitiesDescriptor*> m_groups;
401             vector<const IEntityDescriptor*> m_providers;
402             vector<const IKeyAuthority*> m_keyauths;
403             time_t m_validUntil;
404         };
405
406         XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
407             : ReloadableXMLFileImpl(pathname), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
408         XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
409             : ReloadableXMLFileImpl(e), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
410         void init();
411         ~XMLMetadataImpl();
412
413         typedef multimap<string,const EntityDescriptor*> sitemap_t;
414         typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
415         sitemap_t m_sites;
416         sitemap_t m_sources;
417         groupmap_t m_groups;
418         EntityDescriptor* m_rootProvider;
419         EntitiesDescriptor* m_rootGroup;
420         const XMLMetadata* m_outer;
421     };
422
423     class XMLMetadata : public IMetadata, public ReloadableXMLFile
424     {
425     public:
426         XMLMetadata(const DOMElement* e);
427         ~XMLMetadata() {delete m_credResolver;}
428
429         const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
430         const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
431         const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
432         const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
433         const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
434         pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
435         
436         bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
437         
438     protected:
439         virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
440         virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
441         
442     private:
443         bool m_exclusions,m_verify;
444         set<string> m_set;
445         ICredResolver* m_credResolver;
446     };
447 }
448
449 IPlugIn* XMLMetadataFactory(const DOMElement* e)
450 {
451     auto_ptr<XMLMetadata> m(new XMLMetadata(e));
452     m->getImplementation();
453     return m.release();
454 }
455
456 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
457 {
458     return new XMLMetadataImpl(e,this);
459 }
460
461 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
462 {
463     return new XMLMetadataImpl(pathname,this);
464 }
465
466 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
467 {
468     const XMLCh* type=NULL;
469     
470     // Old metadata or new?
471     if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
472         type=e->getAttributeNS(NULL,SHIB_L(Type));
473         auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
474         m_surName=wrapper;
475         if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
476             auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
477             if (temp.get())
478                 m_emails.push_back(temp.get());
479         }
480     }
481     else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
482         type=e->getAttributeNS(NULL,SHIB_L(contactType));
483         e=saml::XML::getFirstChildElement(e);
484         while (e) {
485             if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company)) && e->hasChildNodes()) {
486                 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
487                 m_company=wrapper;
488             }
489             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName)) && e->hasChildNodes()) {
490                 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
491                 m_givenName=wrapper;
492             }
493             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName)) && e->hasChildNodes()) {
494                 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
495                 m_surName=wrapper;
496             }
497             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress)) && e->hasChildNodes()) {
498                 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
499                 if (temp.get()) m_emails.push_back(temp.get());
500             }
501             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber)) && e->hasChildNodes()) {
502                 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
503                 if (temp.get()) m_phones.push_back(temp.get());
504             }
505             e=saml::XML::getNextSiblingElement(e);
506         }
507     }
508     
509     if (!XMLString::compareString(type,SHIB_L(technical)))
510         m_type=IContactPerson::technical;
511     else if (!XMLString::compareString(type,SHIB_L(support)))
512         m_type=IContactPerson::support;
513     else if (!XMLString::compareString(type,SHIB_L(administrative)))
514         m_type=IContactPerson::administrative;
515     else if (!XMLString::compareString(type,SHIB_L(billing)))
516         m_type=IContactPerson::billing;
517     else if (!XMLString::compareString(type,SHIB_L(other)))
518         m_type=IContactPerson::other;
519 }
520
521 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
522 {
523     DOMNode* n=NULL;
524     e=saml::XML::getFirstChildElement(e);
525     while (e) {
526         if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
527             n=e->getFirstChild();
528             if (n) {
529                 auto_ptr<char> name(toUTF8(n->getNodeValue()));
530                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
531                 m_names[lang.get()]=name.get();
532             }
533         }
534         else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
535             n=e->getFirstChild();
536             if (n) {
537                 auto_ptr<char> display(toUTF8(n->getNodeValue()));
538                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
539                 m_displays[lang.get()]=display.get();
540             }
541         }
542         else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
543             n=e->getFirstChild();
544             if (n) {
545                 auto_ptr<char> url(toUTF8(n->getNodeValue()));
546                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
547                 m_urls[lang.get()]=url.get();
548             }
549         }
550         e=saml::XML::getNextSiblingElement(e);
551     }
552 }
553
554 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
555 {
556     m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
557     e=saml::XML::getFirstChildElement(e);
558     while (e) {
559         if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
560             DOMNode* n=e->getFirstChild();
561             if (n) m_size=XMLString::parseInt(n->getNodeValue());
562         }
563         else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
564             DOMNode* n=e->getFirstChild();
565             if (n) m_digest=n->getNodeValue();
566         }
567         else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
568             DOMNode* n=e->getFirstChild();
569             if (n) m_params=n->getNodeValue();
570         }
571         e=saml::XML::getNextSiblingElement(e);
572     }
573 }
574
575 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
576 {
577 #ifdef _DEBUG
578     saml::NDC ndc("KeyDescriptor");
579 #endif
580     if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
581         m_use=encryption;
582     else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
583         m_use=signing;
584     
585     m_klist = new DSIGKeyInfoList(NULL);
586
587     // Process ds:KeyInfo
588     e=saml::XML::getFirstChildElement(e);
589
590     // We let XMLSec hack through anything it can. This should evolve over time, or we can
591     // plug in our own KeyResolver later...
592     try {
593         if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
594             Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
595                 "skipping ds:KeyInfo element containing unsupported children"
596                 );
597     }
598     catch (XSECCryptoException& xe) {
599         Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
600     }
601     
602     // Check for encryption methods.
603     e=saml::XML::getNextSiblingElement(e);
604     while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
605         m_methods.push_back(new EncryptionMethod(e));
606 }
607
608 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
609 {
610     for_each(m_methods.begin(),m_methods.end(),cleanup<XENCEncryptionMethod>);
611     delete m_klist;
612 }
613
614 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
615 {
616 #ifdef _DEBUG
617     saml::NDC ndc("KeyAuthority");
618 #endif
619     if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
620         m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
621     
622     // Process ds:KeyInfo children
623     e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
624     while (e) {
625         auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
626
627         // We let XMLSec hack through anything it can. This should evolve over time, or we can
628         // plug in our own KeyResolver later...
629         DOMElement* child=saml::XML::getFirstChildElement(e);
630         while (child) {
631             try {
632                 if (!klist->addXMLKeyInfo(child)) {
633                     Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
634                         "skipped unresolvable ds:KeyInfo child element");
635                 }
636             }
637             catch (XSECCryptoException& xe) {
638                 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
639                     "unable to process ds:KeyInfo child element: %s",xe.getMsg());
640             }
641             child=saml::XML::getNextSiblingElement(child);
642         }
643         
644         if (klist->getSize()>0)
645             m_klists.push_back(klist.release());
646         else
647             Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
648                 "skipping ds:KeyInfo with no resolvable child elements");
649         e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
650     }
651 }
652
653 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
654 {
655     for_each(m_klists.begin(),m_klists.end(),cleanup<DSIGKeyInfoList>);
656 }
657
658 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
659     : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
660 {
661     // Check the root element namespace. If SAML2, assume it's the std schema.
662     if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
663        
664         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
665             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
666             exp.parseDateTime();
667             m_validUntil=min(m_validUntil,exp.getEpoch());
668         }
669         
670         if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
671             m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
672         
673         // Chop the protocol list into pieces...assume any whitespace can appear in between.
674         m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
675         XMLCh* temp=m_protocolEnumCopy;
676         while (temp && *temp) {
677             XMLCh* start=temp++;
678             while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
679             if (*temp)
680                 *temp++=chNull;
681             m_protocolEnum.push_back(start);
682             while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
683         }
684         
685         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
686         while (e) {
687             m_keys.push_back(new KeyDescriptor(e));
688             e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
689         }
690
691         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
692         if (e)
693             m_org=new Organization(e);
694
695         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
696         while (e) {
697             m_contacts.push_back(new ContactPerson(e));
698             e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
699         }
700     }
701 }
702
703 XMLMetadataImpl::Role::~Role()
704 {
705     delete m_org;
706     delete m_errorURL;
707     if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
708     for_each(m_keys.begin(),m_keys.end(),cleanup<IKeyDescriptor>);
709     for_each(m_contacts.begin(),m_contacts.end(),cleanup<IContactPerson>);
710 }
711
712 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
713 {
714     Iterator<const XMLCh*> i(m_protocolEnum);
715     while (i.hasNext()) {
716         if (!XMLString::compareString(protocol,i.next()))
717             return true;
718     }
719     return false;
720 }
721
722 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
723     : Role(provider,validUntil,e)
724 {
725     // Check the root element namespace. If SAML2, assume it's the std schema.
726     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
727         unsigned int i;
728         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
729         for (i=0; nlist && i<nlist->getLength(); i++)
730             m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
731
732         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
733         for (i=0; nlist && i<nlist->getLength(); i++)
734             m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
735
736         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
737         for (i=0; nlist && i<nlist->getLength(); i++)
738             m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
739
740         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
741         for (i=0; nlist && i<nlist->getLength(); i++) {
742             DOMNode* n=nlist->item(i)->getFirstChild();
743             if (n) m_formats.push_back(n->getNodeValue());
744         }
745     }
746     else {
747         // For old style, we just do SAML 1.1 compatibility with Shib handles.
748         m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
749         m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
750     }
751 }
752
753 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
754 {
755     // Check the root element namespace. If SAML2, assume it's the std schema.
756     DOMNodeList* nlist=NULL;
757     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
758         e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
759         if (e) nlist=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
760     }
761     else {
762         nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
763     }
764     
765     for (unsigned int i=0; nlist && i < nlist->getLength(); i++) {
766         const XMLCh* dom=(nlist->item(i)->hasChildNodes()) ? nlist->item(i)->getFirstChild()->getNodeValue() : NULL;
767         if (dom && *dom) {
768             const XMLCh* regexp=static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
769             m_scopes.push_back(
770                 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
771                 );
772         }
773     }
774 }
775
776 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
777     : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
778 {
779     // Check the root element namespace. If SAML2, assume it's the std schema.
780     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
781         const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
782         m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
783         
784         // Check for SourceID extension.
785         DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
786         if (ext) {
787             ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
788             if (ext && ext->hasChildNodes())
789                 m_sourceId=ext->getFirstChild()->getNodeValue();
790         }
791         
792         unsigned int i;
793         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
794         for (i=0; nlist && i<nlist->getLength(); i++)
795             m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
796
797         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
798         for (i=0; nlist && i<nlist->getLength(); i++)
799             m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
800
801         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
802         for (i=0; nlist && i<nlist->getLength(); i++)
803             m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
804
805         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
806         for (i=0; nlist && i<nlist->getLength(); i++) {
807             DOMNode* n=nlist->item(i)->getFirstChild();
808             if (n) m_attrprofs.push_back(n->getNodeValue());
809         }
810
811         nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
812         for (i=0; nlist && i<nlist->getLength(); i++) {
813             // For now, we need to convert these to plain SAML 1.1 attributes.
814             DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
815             DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
816             copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
817             copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
818             src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
819             while (src) {
820                 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
821                 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
822                 DOMNamedNodeMap* attrs = src->getAttributes();
823                 for (unsigned int j=0; j<attrs->getLength(); j++)
824                     val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
825                 while (src->hasChildNodes())
826                     val->appendChild(src->getFirstChild());
827                 copy->appendChild(val);
828             }
829             m_attrs.push_back(SAMLAttribute::getInstance(copy));
830         }
831     }
832     else {
833         m_protocolEnum.push_back(Constants::SHIB_NS);
834         m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
835         unsigned int i;
836         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
837         for (i=0; nlist && i<nlist->getLength(); i++) {
838             // Manufacture an endpoint for the "Shib" binding.
839             m_sso.add(
840                 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
841                 );
842
843             // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
844             DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
845             DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
846             DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
847             kn->appendChild(
848                 e->getOwnerDocument()->createTextNode(
849                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
850                     )
851                 );
852             ki->appendChild(kn);
853             kd->appendChild(ki);
854             kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
855             m_keys.push_back(new KeyDescriptor(kd));
856         }
857     }
858 }
859
860 XMLMetadataImpl::IDPRole::~IDPRole()
861 {
862     for_each(m_attrs.begin(),m_attrs.end(),cleanup<SAMLAttribute>);
863 }
864
865 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
866     : Role(provider,validUntil,e), ScopedRole(e)
867 {
868     // Check the root element namespace. If SAML2, assume it's the std schema.
869     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
870         unsigned int i;
871         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
872         for (i=0; nlist && i<nlist->getLength(); i++)
873             m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
874
875         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
876         for (i=0; nlist && i<nlist->getLength(); i++)
877             m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
878
879         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
880         for (i=0; nlist && i<nlist->getLength(); i++) {
881             DOMNode* n=nlist->item(i)->getFirstChild();
882             if (n) m_formats.push_back(n->getNodeValue());
883         }
884
885         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
886         for (i=0; nlist && i<nlist->getLength(); i++) {
887             DOMNode* n=nlist->item(i)->getFirstChild();
888             if (n) m_attrprofs.push_back(n->getNodeValue());
889         }
890
891         nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
892         for (i=0; nlist && i<nlist->getLength(); i++) {
893             // For now, we need to convert these to plain SAML 1.1 attributes.
894             DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
895             DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
896             copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
897             copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
898             src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
899             while (src) {
900                 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
901                 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
902                 DOMNamedNodeMap* attrs = src->getAttributes();
903                 for (unsigned int j=0; j<attrs->getLength(); j++)
904                     val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
905                 while (src->hasChildNodes())
906                     val->appendChild(src->getFirstChild());
907                 copy->appendChild(val);
908             }
909             m_attrs.push_back(SAMLAttribute::getInstance(copy));
910         }
911     }
912     else {
913         // For old style, we just do SAML 1.1 compatibility with Shib handles.
914         m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
915         m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
916         m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
917         unsigned int i;
918         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
919         for (i=0; nlist && i<nlist->getLength(); i++) {
920             // Manufacture an endpoint for the SOAP binding.
921             m_query.add(
922                 new Endpoint(
923                     SAMLBinding::SOAP,
924                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
925                     )
926                 );
927
928             // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
929             DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
930             DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
931             DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
932             kn->appendChild(
933                 e->getOwnerDocument()->createTextNode(
934                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
935                     )
936                 );
937             ki->appendChild(kn);
938             kd->appendChild(ki);
939             m_keys.push_back(new KeyDescriptor(kd));
940         }
941     }
942 }
943
944 XMLMetadataImpl::AARole::~AARole()
945 {
946     for_each(m_attrs.begin(),m_attrs.end(),cleanup<SAMLAttribute>);
947 }
948
949 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
950     const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
951     ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
952 {
953     // Check the root element namespace. If SAML2, assume it's the std schema.
954     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
955         m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
956
957         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
958             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
959             exp.parseDateTime();
960             m_validUntil=min(validUntil,exp.getEpoch());
961         }
962
963         DOMElement* child=saml::XML::getFirstChildElement(e);
964         while (child) {
965             // Process the various kinds of children that we care about...
966             if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
967                 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
968                 while (ext) {
969                     m_keyauths.push_back(new KeyAuthority(ext));
970                     ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
971                 }
972             }
973             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
974                 m_contacts.push_back(new ContactPerson(child));
975             }
976             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
977                 m_org=new Organization(child);
978             }
979             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
980                 DOMNode* loc=child->getFirstChild();
981                 if (loc)
982                     m_locs.push_back(
983                     pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
984                         );
985             }
986             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
987                 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
988                     m_roles.push_back(new IDPRole(this,m_validUntil,child));
989             }
990             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
991                 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
992                     m_roles.push_back(new AARole(this,m_validUntil,child));
993             }
994             child = saml::XML::getNextSiblingElement(child);
995         }
996     }
997     else {
998         m_id=e->getAttributeNS(NULL,SHIB_L(Name));
999         auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
1000         m_errorURL=wrapper;
1001         
1002         bool idp=false,aa=false;    // only want to build a role once
1003         DOMElement* child=saml::XML::getFirstChildElement(e);
1004         while (child) {
1005             // Process the various kinds of OriginSite children that we care about...
1006             if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
1007                 m_contacts.push_back(new ContactPerson(child));
1008             }
1009             else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
1010                 // Create the IDP role if needed.
1011                 m_roles.push_back(new IDPRole(this, m_validUntil, e));
1012                 idp=true;
1013             }
1014             else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
1015                 // Create the AA role if needed.
1016                 m_roles.push_back(new AARole(this, m_validUntil, e));
1017                 aa=true;
1018             }
1019             child = saml::XML::getNextSiblingElement(child);
1020         }
1021     }
1022
1023     auto_ptr_char id(m_id);
1024     wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1025     
1026     // Look for an IdP role, and register the artifact source ID and endpoints.
1027     const IDPRole* idp=NULL;
1028     for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1029         if (idp=dynamic_cast<const IDPRole*>(*r)) {
1030             if (idp->m_sourceId) {
1031                 auto_ptr_char sourceid(idp->m_sourceId);
1032                 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1033             }
1034             else {
1035                 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1036                 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1037             }
1038             Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1039             while (locs.hasNext()) {
1040                 auto_ptr_char loc(locs.next()->getLocation());
1041                 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1042             }
1043         }
1044     }
1045 }
1046
1047 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1048 {
1049     const IIDPSSODescriptor* ret=NULL;
1050     for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1051         if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1052             return ret;
1053     }
1054     return NULL;
1055 }
1056
1057 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1058 {
1059     const IAttributeAuthorityDescriptor* ret=NULL;
1060     for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1061         if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1062             return ret;
1063     }
1064     return NULL;
1065 }
1066
1067 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1068 {
1069     delete m_org;
1070     for_each(m_contacts.begin(),m_contacts.end(),cleanup<IContactPerson>);
1071     for_each(m_roles.begin(),m_roles.end(),cleanup<IRoleDescriptor>);
1072     for_each(m_keyauths.begin(),m_keyauths.end(),cleanup<IKeyAuthority>);
1073 }
1074
1075 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1076     const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1077     ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1078 {
1079     // Check the root element namespace. If SAML2, assume it's the std schema.
1080     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1081
1082         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1083             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1084             exp.parseDateTime();
1085             m_validUntil=min(validUntil,exp.getEpoch());
1086         }
1087
1088         e=saml::XML::getFirstChildElement(e);
1089         while (e) {
1090             if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1091                 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1092                 while (ext) {
1093                     m_keyauths.push_back(new KeyAuthority(ext));
1094                     ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1095                 }
1096             }
1097             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1098                 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1099                     m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1100             }
1101             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1102                 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1103                     m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1104             }
1105             e=saml::XML::getNextSiblingElement(e);
1106         }
1107     }
1108     else {
1109         e=saml::XML::getFirstChildElement(e);
1110         while (e) {
1111             if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1112                 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1113                     m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1114             }
1115             else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1116                 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1117             e=saml::XML::getNextSiblingElement(e);
1118         }
1119     }
1120
1121     if (!saml::XML::isEmpty(m_name)) {
1122         auto_ptr_char n(m_name);
1123         wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1124     }
1125     else
1126         m_name=NULL;
1127 }
1128
1129 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1130 {
1131     for_each(m_providers.begin(),m_providers.end(),cleanup<IEntityDescriptor>);
1132     for_each(m_groups.begin(),m_groups.end(),cleanup<IEntitiesDescriptor>);
1133     for_each(m_keyauths.begin(),m_keyauths.end(),cleanup<IKeyAuthority>);
1134 }
1135
1136 void XMLMetadataImpl::init()
1137 {
1138 #ifdef _DEBUG
1139     NDC ndc("init");
1140 #endif
1141     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1142
1143     try
1144     {
1145         if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1146             if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1147                 m_rootGroup=new EntitiesDescriptor(m_root,this);
1148         }
1149         else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1150             if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1151                 m_rootProvider=new EntityDescriptor(m_root,this);
1152         }
1153         else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1154             if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1155                 m_rootGroup=new EntitiesDescriptor(m_root,this);
1156         }
1157         else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1158             if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1159                 m_rootProvider=new EntityDescriptor(m_root,this);
1160         }
1161         else {
1162             log.error("Construction requires a valid SAML metadata file");
1163             throw MetadataException("Construction requires a valid SAML metadata file");
1164         }
1165     }
1166     catch (SAMLException& e)
1167     {
1168         log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1169         this->~XMLMetadataImpl();
1170         throw;
1171     }
1172 #ifndef _DEBUG
1173     catch (...)
1174     {
1175         log.error("Unexpected error while parsing SAML metadata");
1176         this->~XMLMetadataImpl();
1177         throw;
1178     }
1179 #endif
1180
1181     if (!m_rootGroup && !m_rootProvider) {
1182         log.error("Metadata file contained no valid information");
1183         throw MetadataException("Metadata file contained no valid information");
1184     }
1185 }
1186
1187 XMLMetadataImpl::~XMLMetadataImpl()
1188 {
1189     delete m_rootGroup;
1190     delete m_rootProvider;
1191 }
1192
1193 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1194 {
1195     static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1196     if (e->hasAttributeNS(NULL,uri)) {
1197         // First check for explicit enablement of entities.
1198         DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1199         for (unsigned int i=0; nlist && i<nlist->getLength(); i++) {
1200             if (nlist->item(i)->hasChildNodes()) {
1201                 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1202                 if (temp.get()) {
1203                     m_set.insert(temp.get());
1204                     m_exclusions=false;
1205                 }
1206             }
1207         }
1208         // If there was no explicit enablement, build a set of exclusions.
1209         if (m_exclusions) {
1210             nlist=e->getElementsByTagName(SHIB_L(Exclude));
1211             for (unsigned int j=0; nlist && j<nlist->getLength(); j++) {
1212                 if (nlist->item(j)->hasChildNodes()) {
1213                     auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1214                     if (temp.get())
1215                         m_set.insert(temp.get());
1216                 }
1217             }
1218         }
1219     }
1220     
1221     const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1222     m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1223
1224     string cr_type;
1225     DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1226     if (r)
1227         cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";            
1228     else {
1229         r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1230         if (r) {
1231             auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1232             cr_type=c.get();
1233         }
1234     }
1235     
1236     if (!cr_type.empty()) {
1237         try {
1238             IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1239             ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1240             if (cr)
1241                 m_credResolver=cr;
1242             else {
1243                 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1244                 delete plugin;
1245                 throw UnsupportedExtensionException("plugin was not a credential resolver");
1246             }
1247         }
1248         catch (SAMLException& e) {
1249             Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1250             throw;
1251         }
1252     }
1253     
1254     if (m_verify && !m_credResolver) {
1255         delete m_credResolver;
1256         throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1257     }
1258 }
1259
1260 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1261 {
1262     if (!m_verify)
1263         return true;
1264
1265 #ifdef _DEBUG
1266     saml::NDC ndc("verifySignature");
1267 #endif
1268     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1269     
1270     DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1271     if (!sigNode) {
1272         if (failUnsigned) {
1273             log.error("rejecting unsigned element");
1274             return false;
1275         }
1276         return true;
1277     }
1278     
1279     XSECCryptoX509* cert=NULL;
1280     Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1281     if (certs.hasNext())
1282         cert=certs.next();
1283     else {
1284         log.error("unable to find any certificates to use in verifying signature");
1285         return false;
1286     }
1287
1288     static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1289     static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1290
1291     // Load the signature.
1292     XSECProvider prov;
1293     DSIGSignature* sig=NULL;
1294     try {
1295         sig=prov.newSignatureFromDOM(doc,sigNode);
1296         sig->load();
1297
1298         bool valid=false;
1299         const XMLCh* URI=NULL;
1300
1301         // Verify the signature coverage.
1302         DSIGReferenceList* refs=sig->getReferenceList();
1303         if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1304             DSIGReference* ref=refs->item(0);
1305             if (ref) {
1306                 URI=ref->getURI();
1307                 if (!URI || !*URI || (*URI==chPound &&
1308                         !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1309                     DSIGTransformList* tlist=ref->getTransforms();
1310                     for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
1311                         if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1312                             valid=true;
1313                         else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1314                                  tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1315                             valid=false;
1316                             break;
1317                         }
1318                     }
1319                 }
1320             }
1321         }
1322     
1323         if (!valid) {
1324             auto_ptr_char temp((URI && *URI) ? URI : null);
1325             log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1326             return false;
1327         }
1328         
1329         sig->setSigningKey(cert->clonePublicKey());
1330         if (!sig->verify()) {
1331             auto_ptr_char temp((URI && *URI) ? URI : null);
1332             log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1333             return false;
1334         }
1335         
1336         prov.releaseSignature(sig);
1337     }
1338     catch(XSECException& e) {
1339         auto_ptr_char msg(e.getMsg());
1340         log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << CategoryStream::ENDLINE;
1341         if (sig)
1342             prov.releaseSignature(sig);
1343         return false;
1344     }
1345     catch(XSECCryptoException& e) {
1346         log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << CategoryStream::ENDLINE;
1347         if (sig)
1348             prov.releaseSignature(sig);
1349         return false;
1350     }
1351     catch(...) {
1352         if (sig)
1353             prov.releaseSignature(sig);
1354         log.error("caught unknown exception while verifying metadata signature");
1355         throw;
1356     }
1357     return true;
1358 }
1359
1360 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1361 {
1362     if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1363         return NULL;
1364     else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1365         return NULL;
1366         
1367     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1368     pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1369         impl->m_sites.equal_range(providerId);
1370
1371     time_t now=time(NULL);
1372     for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1373         if (now < i->second->getValidUntil())
1374             return i->second;
1375     
1376     if (!strict && range.first!=range.second)
1377         return range.first->second;
1378         
1379     return NULL;
1380 }
1381
1382 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1383 {
1384     auto_ptr_char temp(providerId);
1385     return lookup(temp.get(),strict);
1386 }
1387
1388 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1389 {
1390     time_t now=time(NULL);
1391     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1392     pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1393     
1394     // Depends on type of artifact.
1395     const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1396     if (type1) {
1397         range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1398     }
1399     else {
1400         const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1401         if (type2) {
1402             range=impl->m_sources.equal_range(type2->getSourceLocation());
1403         }
1404         else
1405             return NULL;
1406     }
1407
1408     // Check exclude list.
1409     if (range.first!=range.second) {
1410         auto_ptr_char id(range.first->second->getId());
1411         if (m_exclusions && m_set.find(id.get())!=m_set.end())
1412             return NULL;
1413         else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1414             return NULL;
1415
1416         for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1417             if (now < i->second->getValidUntil())
1418                 return i->second;
1419     }
1420     
1421     return NULL;
1422 }
1423
1424 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1425 {
1426     if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1427         return NULL;
1428     else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1429         return NULL;
1430         
1431     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1432     pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1433         impl->m_groups.equal_range(name);
1434
1435     time_t now=time(NULL);
1436     for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1437         if (now < i->second->getValidUntil())
1438             return i->second;
1439     
1440     if (!strict && range.first!=range.second)
1441         return range.first->second;
1442         
1443     return NULL;
1444 }
1445
1446 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1447 {
1448     auto_ptr_char temp(name);
1449     return lookupGroup(temp.get(),strict);
1450 }
1451
1452 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1453 {
1454     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1455     return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);
1456 }
1457