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