Nasty off by 1 bug.
[shibboleth/cpp-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 Role : public virtual IRoleDescriptor
164         {
165         public:
166             Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
167             ~Role();
168             
169             // External contract
170             const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
171             Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
172             bool hasSupport(const XMLCh* protocol) const;
173             const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
174             bool isValid() const {return time(NULL) < m_validUntil;}
175             Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
176             const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
177             Iterator<const IContactPerson*> getContactPersons() const
178                 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
179             const DOMElement* getElement() const {return m_root;}
180         
181         protected:
182             vector<const XMLCh*> m_protocolEnum;
183             vector<const IKeyDescriptor*> m_keys;
184
185         private:
186             const EntityDescriptor* m_provider;
187             const DOMElement* m_root;
188             XMLCh* m_protocolEnumCopy;
189             char* m_errorURL;
190             Organization* m_org;
191             vector<const IContactPerson*> m_contacts;
192             time_t m_validUntil;
193         };
194         
195         class Endpoint : public virtual IEndpoint
196         {
197         public:
198             Endpoint(const DOMElement* e) : m_root(e),
199                 m_binding(e->getAttributeNS(NULL,L(Binding))),
200                 m_location(e->getAttributeNS(NULL,SHIB_L(Location))),
201                 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
202             Endpoint(const XMLCh* binding, const XMLCh* loc)
203                 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
204             ~Endpoint() {}
205             
206             const XMLCh* getBinding() const { return m_binding; }
207             const XMLCh* getLocation() const { return m_location; }
208             const XMLCh* getResponseLocation() const { return m_resploc; }
209             const DOMElement* getElement() const { return m_root; }
210         
211         private:
212             const DOMElement* m_root;
213             const XMLCh* m_binding;
214             const XMLCh* m_location;
215             const XMLCh* m_resploc;
216         };
217         
218         class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
219         {
220         public:
221             IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
222             unsigned short getIndex() const {return m_index;}
223             
224         private:
225             unsigned short m_index;
226         };
227         
228         class EndpointManager : public IEndpointManager
229         {
230         public:
231             EndpointManager() : m_soft(NULL), m_hard(NULL) {}
232             ~EndpointManager() {
233                 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
234                     delete const_cast<IEndpoint*>(*i);
235             }
236             saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
237             const IEndpoint* getDefaultEndpoint() const {
238                 if (m_hard) return m_hard;
239                 if (m_soft) return m_soft;
240                 if (!m_endpoints.empty()) return *(m_endpoints.begin());
241                 return NULL;
242             }
243             const IEndpoint* getEndpointByIndex(unsigned short index) const {
244                 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
245                     const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
246                     if (temp && index==temp->getIndex())
247                         return temp;
248                 }
249                 return NULL;
250             }
251             const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
252                 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
253                     if (!XMLString::compareString(binding,(*i)->getBinding()))
254                         return *i;
255                 return NULL;
256             }
257             void add(IEndpoint* e) {
258                 m_endpoints.push_back(e);
259                 if (!m_hard && e->getElement()) {
260                     const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
261                     if (v && (*v==chDigit_1 || *v==chLatin_t))  // explicit default
262                         m_hard=e;
263                     else if ((!v || !*v) && !m_soft)            // implicit default
264                         m_soft=e;
265                 }
266                 else if (!m_hard && !m_soft) {
267                     // No default yet, so this one qualifies as an implicit.
268                     m_soft=e;
269                 }
270             }
271             
272         private:
273             vector<const IEndpoint*> m_endpoints;
274             const IEndpoint* m_soft;    // Soft default (not explicit)
275             const IEndpoint* m_hard;    // Hard default (explicit)
276         };
277         
278         class SSORole : public Role, public virtual ISSODescriptor
279         {
280         public:
281             SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
282             ~SSORole() {}
283             const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
284             const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
285             const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
286             saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
287             
288         private:
289             EndpointManager m_artifact,m_logout,m_nameid;
290             vector<const XMLCh*> m_formats;
291         };
292
293         class ScopedRole : public virtual IScopedRoleDescriptor
294         {
295         public:
296             ScopedRole(const DOMElement* e);
297             saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
298
299         private:
300             vector<pair<const XMLCh*,bool> > m_scopes;
301         };
302         
303         class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
304         {
305         public:
306             IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
307             ~IDPRole();
308             bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
309             const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
310             const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
311             const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
312             saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
313             saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
314         
315         private:
316             EndpointManager m_sso,m_mapping,m_idreq;
317             vector<const XMLCh*> m_attrprofs;
318             vector<const SAMLAttribute*> m_attrs;
319             bool m_wantAuthnRequestsSigned;
320             const XMLCh* m_sourceId;
321             friend class EntityDescriptor;
322         };
323
324         class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
325         {
326         public:
327             AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
328             ~AARole();
329             const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
330             const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
331             saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
332             saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
333             saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
334         
335         private:
336             EndpointManager m_query,m_idreq;
337             vector<const XMLCh*> m_formats,m_attrprofs;
338             vector<const SAMLAttribute*> m_attrs;
339         };
340     
341         class EntityDescriptor : public IEntityDescriptor
342         {
343         public:
344             EntityDescriptor(
345                 const DOMElement* e,
346                 XMLMetadataImpl* wrapper,
347                 time_t validUntil=LONG_MAX,
348                 const IEntitiesDescriptor* parent=NULL
349                 );
350             ~EntityDescriptor();
351         
352             // External contract
353             const XMLCh* getId() const {return m_id;}
354             bool isValid() const {return time(NULL) < m_validUntil;}
355             Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
356             const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
357             const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
358             const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
359             const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
360             const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
361             const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
362             const IOrganization* getOrganization() const {return m_org;}
363             Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
364             saml::Iterator<std::pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
365             const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
366             const DOMElement* getElement() const {return m_root;}
367
368             // Used internally
369             const char* getErrorURL() const {return m_errorURL.get();}
370             time_t getValidUntil() const {return m_validUntil;}
371         private:
372             const DOMElement* m_root;
373             const IEntitiesDescriptor* m_parent;
374             const XMLCh* m_id;
375             auto_ptr<char> m_errorURL;
376             IOrganization* m_org;
377             vector<const IContactPerson*> m_contacts;
378             vector<const IRoleDescriptor*> m_roles;
379             vector<pair<const XMLCh*,const XMLCh*> > m_locs;
380             time_t m_validUntil;
381         };
382
383         class EntitiesDescriptor : public IEntitiesDescriptor
384         {
385         public:
386             EntitiesDescriptor(
387                 const DOMElement* e,
388                 XMLMetadataImpl* wrapper,
389                 time_t validUntil=LONG_MAX,
390                 const IEntitiesDescriptor* parent=NULL
391                 );
392             ~EntitiesDescriptor();
393             
394             const XMLCh* getName() const {return m_name;}
395             bool isValid() const {return time(NULL) < m_validUntil;}
396             const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
397             saml::Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
398             saml::Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
399             const DOMElement* getElement() const {return m_root;}
400         
401         private:
402             const DOMElement* m_root;
403             const IEntitiesDescriptor* m_parent;
404             const XMLCh* m_name;
405             vector<const IEntitiesDescriptor*> m_groups;
406             vector<const IEntityDescriptor*> m_providers;
407             time_t m_validUntil;
408         };
409
410         XMLMetadataImpl(const char* pathname) : ReloadableXMLFileImpl(pathname), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
411         XMLMetadataImpl(const DOMElement* e) : ReloadableXMLFileImpl(e), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
412         void init();
413         ~XMLMetadataImpl();
414
415         typedef multimap<string,const EntityDescriptor*> sitemap_t;
416         sitemap_t m_sites;
417         sitemap_t m_sources;
418         EntityDescriptor* m_rootProvider;
419         EntitiesDescriptor* m_rootGroup;
420     };
421
422     class XMLMetadata : public IMetadata, public ReloadableXMLFile
423     {
424     public:
425         XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e) {}
426         ~XMLMetadata() {}
427
428         const IEntityDescriptor* lookup(const XMLCh* providerId) const;
429         const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
430         
431     protected:
432         virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
433         virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
434     };
435 }
436
437 IPlugIn* XMLMetadataFactory(const DOMElement* e)
438 {
439     auto_ptr<XMLMetadata> m(new XMLMetadata(e));
440     m->getImplementation();
441     return m.release();
442 }
443
444 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
445 {
446     return new XMLMetadataImpl(e);
447 }
448
449 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
450 {
451     return new XMLMetadataImpl(pathname);
452 }
453
454 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
455 {
456     const XMLCh* type=NULL;
457     
458     // Old metadata or new?
459     if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
460         type=e->getAttributeNS(NULL,SHIB_L(Type));
461         m_surName=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
462         if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
463             auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
464             if (temp.get())
465                 m_emails.push_back(temp.get());
466         }
467     }
468     else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
469         type=e->getAttributeNS(NULL,SHIB_L(contactType));
470         DOMNode* n=NULL;
471         e=saml::XML::getFirstChildElement(e);
472         while (e) {
473             if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company))) {
474                 n=e->getFirstChild();
475                 if (n) m_company=auto_ptr<char>(toUTF8(n->getNodeValue()));
476             }
477             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName))) {
478                 n=e->getFirstChild();
479                 if (n) m_givenName=auto_ptr<char>(toUTF8(n->getNodeValue()));
480             }
481             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName))) {
482                 n=e->getFirstChild();
483                 if (n) m_surName=auto_ptr<char>(toUTF8(n->getNodeValue()));
484             }
485             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress))) {
486                 n=e->getFirstChild();
487                 if (n) {
488                     auto_ptr<char> temp(toUTF8(n->getNodeValue()));
489                     if (temp.get()) m_emails.push_back(temp.get());
490                 }
491             }
492             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber))) {
493                 n=e->getFirstChild();
494                 if (n) {
495                     auto_ptr<char> temp(toUTF8(n->getNodeValue()));
496                     if (temp.get()) m_phones.push_back(temp.get());
497                 }
498             }
499             e=saml::XML::getNextSiblingElement(e);
500         }
501     }
502     
503     if (!XMLString::compareString(type,SHIB_L(technical)))
504         m_type=IContactPerson::technical;
505     else if (!XMLString::compareString(type,SHIB_L(support)))
506         m_type=IContactPerson::support;
507     else if (!XMLString::compareString(type,SHIB_L(administrative)))
508         m_type=IContactPerson::administrative;
509     else if (!XMLString::compareString(type,SHIB_L(billing)))
510         m_type=IContactPerson::billing;
511     else if (!XMLString::compareString(type,SHIB_L(other)))
512         m_type=IContactPerson::other;
513 }
514
515 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
516 {
517     DOMNode* n=NULL;
518     e=saml::XML::getFirstChildElement(e);
519     while (e) {
520         if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
521             n=e->getFirstChild();
522             if (n) {
523                 auto_ptr<char> name(toUTF8(n->getNodeValue()));
524                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
525                 m_names[lang.get()]=name.get();
526             }
527         }
528         else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
529             n=e->getFirstChild();
530             if (n) {
531                 auto_ptr<char> display(toUTF8(n->getNodeValue()));
532                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
533                 m_displays[lang.get()]=display.get();
534             }
535         }
536         else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
537             n=e->getFirstChild();
538             if (n) {
539                 auto_ptr<char> url(toUTF8(n->getNodeValue()));
540                 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
541                 m_urls[lang.get()]=url.get();
542             }
543         }
544         e=saml::XML::getNextSiblingElement(e);
545     }
546 }
547
548 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
549 {
550     m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
551     e=saml::XML::getFirstChildElement(e);
552     while (e) {
553         if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
554             DOMNode* n=e->getFirstChild();
555             if (n) m_size=XMLString::parseInt(n->getNodeValue());
556         }
557         else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
558             DOMNode* n=e->getFirstChild();
559             if (n) m_digest=n->getNodeValue();
560         }
561         else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
562             DOMNode* n=e->getFirstChild();
563             if (n) m_params=n->getNodeValue();
564         }
565         e=saml::XML::getNextSiblingElement(e);
566     }
567 }
568
569 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
570 {
571     if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
572         m_use=encryption;
573     else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
574         m_use=signing;
575     
576     m_klist = new DSIGKeyInfoList(NULL);
577
578     // Process ds:KeyInfo
579     e=saml::XML::getFirstChildElement(e);
580
581     // We let XMLSec hack through anything it can. This should evolve over time, or we can
582     // plug in our own KeyResolver later...
583     DOMElement* child=saml::XML::getFirstChildElement(e);
584     while (child) {
585         try {
586             if (!m_klist->addXMLKeyInfo(child)) {
587                 Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl.KeyDescriptor").warn(
588                     "skipped unsupported ds:KeyInfo child element");
589             }
590         }
591         catch (XSECCryptoException& xe) {
592             Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl.KeyDescriptor").error(
593                 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
594         }
595         child=saml::XML::getNextSiblingElement(child);
596     }
597     
598     // Check for encryption methods.
599     e=saml::XML::getNextSiblingElement(e);
600     while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
601         m_methods.push_back(new EncryptionMethod(e));
602 }
603
604 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
605 {
606     for (vector<const XENCEncryptionMethod*>::iterator i=m_methods.begin(); i!=m_methods.end(); i++)
607         delete const_cast<XENCEncryptionMethod*>(*i);
608     delete m_klist;
609 }
610
611 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
612     : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
613 {
614     // Check the root element namespace. If SAML2, assume it's the std schema.
615     if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
616        
617         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
618             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
619             exp.parseDateTime();
620             m_validUntil=min(m_validUntil,exp.getEpoch());
621         }
622         
623         if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
624             m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
625         
626         // Chop the protocol list into pieces...assume any whitespace can appear in between.
627         m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
628         XMLCh* temp=m_protocolEnumCopy;
629         while (temp && *temp) {
630             XMLCh* start=temp++;
631             while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
632             if (*temp)
633                 *temp++=chNull;
634             m_protocolEnum.push_back(start);
635             while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
636         }
637         
638         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
639         while (e) {
640             m_keys.push_back(new KeyDescriptor(e));
641             e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
642         }
643
644         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
645         if (e)
646             m_org=new Organization(e);
647
648         e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
649         while (e) {
650             m_contacts.push_back(new ContactPerson(e));
651             e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
652         }
653     }
654 }
655
656 XMLMetadataImpl::Role::~Role()
657 {
658     delete m_org;
659     delete m_errorURL;
660     if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
661     for (vector<const IKeyDescriptor*>::iterator i=m_keys.begin(); i!=m_keys.end(); i++)
662         delete const_cast<IKeyDescriptor*>(*i);
663     for (vector<const IContactPerson*>::iterator j=m_contacts.begin(); j!=m_contacts.end(); j++)
664         delete const_cast<IContactPerson*>(*j);
665 }
666
667 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
668 {
669     Iterator<const XMLCh*> i(m_protocolEnum);
670     while (i.hasNext()) {
671         if (!XMLString::compareString(protocol,i.next()))
672             return true;
673     }
674     return false;
675 }
676
677 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
678     : Role(provider,validUntil,e)
679 {
680     // Check the root element namespace. If SAML2, assume it's the std schema.
681     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
682         int i;
683         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
684         for (i=0; nlist && i<nlist->getLength(); i++)
685             m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
686
687         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
688         for (i=0; nlist && i<nlist->getLength(); i++)
689             m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
690
691         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
692         for (i=0; nlist && i<nlist->getLength(); i++)
693             m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
694
695         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
696         for (i=0; nlist && i<nlist->getLength(); i++) {
697             DOMNode* n=nlist->item(i)->getFirstChild();
698             if (n) m_formats.push_back(n->getNodeValue());
699         }
700     }
701     else {
702         // For old style, we just do SAML 1.1 compatibility with Shib handles.
703         m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
704         m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
705     }
706 }
707
708 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
709 {
710     // Check the root element namespace. If SAML2, assume it's the std schema.
711     DOMNodeList* nlist=NULL;
712     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
713         e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
714         nlist=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
715     }
716     else {
717         nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
718     }
719     
720     for (int i=0; nlist && i < nlist->getLength(); i++) {
721         const XMLCh* dom=(nlist->item(i)->hasChildNodes()) ? nlist->item(i)->getFirstChild()->getNodeValue() : NULL;
722         if (dom && *dom) {
723             const XMLCh* regexp=static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
724             m_scopes.push_back(
725                 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
726                 );
727         }
728     }
729 }
730
731 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
732     : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
733 {
734     // Check the root element namespace. If SAML2, assume it's the std schema.
735     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
736         const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
737         m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
738         
739         // Check for SourceID extension.
740         DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
741         if (ext) {
742             ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
743             if (ext && ext->hasChildNodes())
744                 m_sourceId=ext->getFirstChild()->getNodeValue();
745         }
746         
747         int i;
748         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
749         for (i=0; nlist && i<nlist->getLength(); i++)
750             m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
751
752         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
753         for (i=0; nlist && i<nlist->getLength(); i++)
754             m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
755
756         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
757         for (i=0; nlist && i<nlist->getLength(); i++)
758             m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
759
760         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
761         for (i=0; nlist && i<nlist->getLength(); i++) {
762             DOMNode* n=nlist->item(i)->getFirstChild();
763             if (n) m_attrprofs.push_back(n->getNodeValue());
764         }
765
766         nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
767         for (i=0; nlist && i<nlist->getLength(); i++) {
768             // For now, we need to convert these to plain SAML 1.1 attributes.
769             DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
770             DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
771             copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
772             copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
773             src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
774             while (src) {
775                 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
776                 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
777                 DOMNamedNodeMap* attrs = src->getAttributes();
778                 for (int j=0; j<attrs->getLength(); j++)
779                     val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
780                 while (src->hasChildNodes())
781                     val->appendChild(src->getFirstChild());
782                 copy->appendChild(val);
783             }
784             m_attrs.push_back(SAMLAttribute::getInstance(copy));
785         }
786     }
787     else {
788         m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
789         int i;
790         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
791         for (i=0; nlist && i<nlist->getLength(); i++) {
792             // Manufacture an endpoint for the "Shib" binding.
793             m_sso.add(
794                 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Location)))
795                 );
796
797             // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
798             DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
799             DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
800             DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
801             kn->appendChild(
802                 e->getOwnerDocument()->createTextNode(
803                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
804                     )
805                 );
806             ki->appendChild(kn);
807             kd->appendChild(ki);
808             kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
809             m_keys.push_back(new KeyDescriptor(kd));
810         }
811     }
812 }
813
814 XMLMetadataImpl::IDPRole::~IDPRole()
815 {
816     for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
817         delete const_cast<SAMLAttribute*>(*i);
818 }
819
820 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
821     : Role(provider,validUntil,e), ScopedRole(e)
822 {
823     // Check the root element namespace. If SAML2, assume it's the std schema.
824     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
825         int i;
826         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
827         for (i=0; nlist && i<nlist->getLength(); i++)
828             m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
829
830         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
831         for (i=0; nlist && i<nlist->getLength(); i++)
832             m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
833
834         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
835         for (i=0; nlist && i<nlist->getLength(); i++) {
836             DOMNode* n=nlist->item(i)->getFirstChild();
837             if (n) m_formats.push_back(n->getNodeValue());
838         }
839
840         nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
841         for (i=0; nlist && i<nlist->getLength(); i++) {
842             DOMNode* n=nlist->item(i)->getFirstChild();
843             if (n) m_attrprofs.push_back(n->getNodeValue());
844         }
845
846         nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
847         for (i=0; nlist && i<nlist->getLength(); i++) {
848             // For now, we need to convert these to plain SAML 1.1 attributes.
849             DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
850             DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
851             copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
852             copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
853             src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
854             while (src) {
855                 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
856                 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
857                 DOMNamedNodeMap* attrs = src->getAttributes();
858                 for (int j=0; j<attrs->getLength(); j++)
859                     val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
860                 while (src->hasChildNodes())
861                     val->appendChild(src->getFirstChild());
862                 copy->appendChild(val);
863             }
864             m_attrs.push_back(SAMLAttribute::getInstance(copy));
865         }
866     }
867     else {
868         // For old style, we just do SAML 1.1 compatibility with Shib handles.
869         m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
870         m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
871         m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
872         int i;
873         DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
874         for (i=0; nlist && i<nlist->getLength(); i++) {
875             // Manufacture an endpoint for the SOAP binding.
876             m_query.add(
877                 new Endpoint(
878                     SAMLBinding::SOAP,
879                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Location))
880                     )
881                 );
882
883             // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
884             DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
885             DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
886             DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
887             kn->appendChild(
888                 e->getOwnerDocument()->createTextNode(
889                     static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
890                     )
891                 );
892             ki->appendChild(kn);
893             kd->appendChild(ki);
894             m_keys.push_back(new KeyDescriptor(kd));
895         }
896     }
897 }
898
899 XMLMetadataImpl::AARole::~AARole()
900 {
901     for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
902         delete const_cast<SAMLAttribute*>(*i);
903 }
904
905 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
906     const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
907     ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
908 {
909     // Check the root element namespace. If SAML2, assume it's the std schema.
910     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
911         m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
912
913         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
914             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
915             exp.parseDateTime();
916             m_validUntil=min(validUntil,exp.getEpoch());
917         }
918
919         DOMElement* child=saml::XML::getFirstChildElement(e);
920         while (child) {
921             // Process the various kinds of children that we care about...
922             if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
923                 m_contacts.push_back(new ContactPerson(child));
924             }
925             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
926                 m_org=new Organization(child);
927             }
928             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
929                 DOMNode* loc=child->getFirstChild();
930                 if (loc)
931                     m_locs.push_back(
932                     pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
933                         );
934             }
935             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
936                 m_roles.push_back(new IDPRole(this,m_validUntil,child));
937             }
938             else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
939                 m_roles.push_back(new AARole(this,m_validUntil,child));
940             }
941             child = saml::XML::getNextSiblingElement(child);
942         }
943     }
944     else {
945         m_id=e->getAttributeNS(NULL,SHIB_L(Name));
946         m_errorURL=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
947         
948         bool idp=false,aa=false;    // only want to build a role once
949         DOMElement* child=saml::XML::getFirstChildElement(e);
950         while (child) {
951             // Process the various kinds of OriginSite children that we care about...
952             if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
953                 m_contacts.push_back(new ContactPerson(child));
954             }
955             else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
956                 // Create the IDP role if needed.
957                 m_roles.push_back(new IDPRole(this, m_validUntil, e));
958                 idp=true;
959             }
960             else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
961                 // Create the AA role if needed.
962                 m_roles.push_back(new AARole(this, m_validUntil, e));
963                 aa=true;
964             }
965             child = saml::XML::getNextSiblingElement(child);
966         }
967     }
968
969     auto_ptr_char id(m_id);
970     wrapper->m_sites.insert(pair<string,const EntityDescriptor*>(id.get(),this));
971     
972     // Look for an IdP role, and register the artifact source ID and endpoints.
973     const IDPRole* idp=NULL;
974     for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
975         if (idp=dynamic_cast<const IDPRole*>(*r)) {
976             if (idp->m_sourceId) {
977                 auto_ptr_char sourceid(idp->m_sourceId);
978                 wrapper->m_sources.insert(pair<string,const EntityDescriptor*>(sourceid.get(),this));
979             }
980             else {
981                 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
982                 wrapper->m_sources.insert(pair<string,const EntityDescriptor*>(sourceid,this));
983             }
984             Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
985             while (locs.hasNext()) {
986                 auto_ptr_char loc(locs.next()->getLocation());
987                 wrapper->m_sources.insert(pair<string,const EntityDescriptor*>(loc.get(),this));
988             }
989         }
990     }
991 }
992
993 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
994 {
995     const IIDPSSODescriptor* ret=NULL;
996     for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
997         if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
998             return ret;
999     }
1000     return NULL;
1001 }
1002
1003 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1004 {
1005     const IAttributeAuthorityDescriptor* ret=NULL;
1006     for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1007         if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1008             return ret;
1009     }
1010     return NULL;
1011 }
1012
1013 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1014 {
1015     delete m_org;
1016     for (vector<const IContactPerson*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
1017         delete const_cast<IContactPerson*>(*i);
1018     for (vector<const IRoleDescriptor*>::iterator j=m_roles.begin(); j!=m_roles.end(); j++)
1019         delete const_cast<IRoleDescriptor*>(*j);
1020 }
1021
1022 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1023     const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1024     ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1025 {
1026     // Check the root element namespace. If SAML2, assume it's the std schema.
1027     if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1028
1029         if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1030             SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1031             exp.parseDateTime();
1032             m_validUntil=min(validUntil,exp.getEpoch());
1033         }
1034
1035         e=saml::XML::getFirstChildElement(e);
1036         while (e) {
1037             if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor)))
1038                 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1039             else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor)))
1040                 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1041             e=saml::XML::getNextSiblingElement(e);
1042         }
1043     }
1044     else {
1045         e=saml::XML::getFirstChildElement(e);
1046         while (e) {
1047             if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup)))
1048                 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1049             else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1050                 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1051             e=saml::XML::getNextSiblingElement(e);
1052         }
1053     }
1054 }
1055
1056 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1057 {
1058     for (vector<const IEntityDescriptor*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
1059         delete const_cast<IEntityDescriptor*>(*i);
1060     for (vector<const IEntitiesDescriptor*>::iterator j=m_groups.begin(); j!=m_groups.end(); j++)
1061         delete const_cast<IEntitiesDescriptor*>(*j);
1062 }
1063
1064 void XMLMetadataImpl::init()
1065 {
1066 #ifdef _DEBUG
1067     NDC ndc("XMLMetadataImpl");
1068 #endif
1069     Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl");
1070
1071     try
1072     {
1073         if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor)))
1074             m_rootGroup=new EntitiesDescriptor(m_root,this);
1075         else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor)))
1076             m_rootProvider=new EntityDescriptor(m_root,this);
1077         else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup)))
1078             m_rootGroup=new EntitiesDescriptor(m_root,this);
1079         else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite)))
1080             m_rootProvider=new EntityDescriptor(m_root,this);
1081         else {
1082             log.error("Construction requires a valid SAML metadata file");
1083             throw MetadataException("Construction requires a valid SAML metadata file");
1084         }
1085     }
1086     catch (SAMLException& e)
1087     {
1088         log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1089         this->~XMLMetadataImpl();
1090         throw;
1091     }
1092 #ifndef _DEBUG
1093     catch (...)
1094     {
1095         log.error("Unexpected error while parsing SAML metadata");
1096         this->~XMLMetadataImpl();
1097         throw;
1098     }
1099 #endif
1100 }
1101
1102 XMLMetadataImpl::~XMLMetadataImpl()
1103 {
1104     delete m_rootGroup;
1105     delete m_rootProvider;
1106 }
1107
1108 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId) const
1109 {
1110     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1111     auto_ptr_char temp(providerId);
1112     pair<XMLMetadataImpl::sitemap_t::const_iterator,XMLMetadataImpl::sitemap_t::const_iterator> range=
1113         impl->m_sites.equal_range(temp.get());
1114
1115     time_t now=time(NULL);
1116     for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1117         if (now < i->second->getValidUntil())
1118             return i->second;
1119     return NULL;
1120 }
1121
1122 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1123 {
1124     time_t now=time(NULL);
1125     XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1126     pair<XMLMetadataImpl::sitemap_t::const_iterator,XMLMetadataImpl::sitemap_t::const_iterator> range;
1127     
1128     // Depends on type of artifact.
1129     const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1130     if (type1) {
1131         range=impl->m_sources.equal_range(type1->getSourceID());
1132     }
1133     else {
1134         const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1135         if (type2) {
1136             range=impl->m_sources.equal_range(type2->getSourceLocation());
1137         }
1138         else
1139             return NULL;
1140     }
1141     for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1142         if (now < i->second->getValidUntil())
1143             return i->second;
1144     return NULL;
1145 }