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