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