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