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