2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
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.
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
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.
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.
50 /* XMLMetadata.cpp - a metadata implementation that uses an XML-based registry
60 #include <sys/types.h>
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>
69 using namespace shibboleth;
71 using namespace log4cpp;
76 class XMLMetadataImpl : public ReloadableXMLFileImpl
79 class ContactPerson : public IContactPerson
82 ContactPerson(const DOMElement* e);
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; }
94 const DOMElement* m_root;
96 auto_ptr<char> m_givenName,m_surName,m_company;
97 vector<string> m_emails,m_phones;
100 class Organization : public IOrganization
103 Organization(const DOMElement* e);
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; }
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();
116 const DOMElement* m_root;
117 map<string,string> m_names,m_displays,m_urls;
120 class EntityDescriptor;
122 class EncryptionMethod : public XENCEncryptionMethod
125 EncryptionMethod(const DOMElement* e);
126 ~EncryptionMethod() {}
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();}
138 const DOMElement* m_root;
140 const XMLCh* m_digest;
141 const XMLCh* m_params;
145 class KeyDescriptor : public IKeyDescriptor
148 KeyDescriptor(const DOMElement* e);
151 KeyUse getUse() const { return m_use; }
152 DSIGKeyInfoList* getKeyInfo() const { return &m_klist; }
153 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethod() const { return m_methods; }
154 const DOMElement* getElement() const { return m_root; }
157 const DOMElement* m_root;
159 mutable DSIGKeyInfoList m_klist;
160 vector<const XENCEncryptionMethod*> m_methods;
163 class Role : public virtual IRoleDescriptor
166 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
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;}
177 Iterator<const IContactPerson*> getContactPersons() const
178 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
179 const DOMElement* getElement() const {return m_root;}
182 vector<const XMLCh*> m_protocolEnum;
183 vector<const IKeyDescriptor*> m_keys;
186 const EntityDescriptor* m_provider;
187 const DOMElement* m_root;
188 XMLCh* m_protocolEnumCopy;
191 vector<const IContactPerson*> m_contacts;
195 class Endpoint : public virtual IEndpoint
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) {}
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; }
212 const DOMElement* m_root;
213 const XMLCh* m_binding;
214 const XMLCh* m_location;
215 const XMLCh* m_resploc;
218 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
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;}
225 unsigned short m_index;
228 class EndpointManager : public IEndpointManager
231 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
233 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
234 delete const_cast<IEndpoint*>(*i);
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());
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())
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()))
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
263 else if ((!v || !*v) && !m_soft) // implicit default
266 else if (!m_hard && !m_soft) {
267 // No default yet, so this one qualifies as an implicit.
273 vector<const IEndpoint*> m_endpoints;
274 const IEndpoint* m_soft; // Soft default (not explicit)
275 const IEndpoint* m_hard; // Hard default (explicit)
278 class SSORole : public Role, public virtual ISSODescriptor
281 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
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;}
289 EndpointManager m_artifact,m_logout,m_nameid;
290 vector<const XMLCh*> m_formats;
293 class ScopedRole : public virtual IScopedRoleDescriptor
296 ScopedRole(const DOMElement* e);
297 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
300 vector<pair<const XMLCh*,bool> > m_scopes;
303 class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
306 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
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;}
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 //friend class EntityDescriptor;
323 class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
326 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
328 const IEndpointManager* getAttributeServices() const {return &m_query;}
329 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
330 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
331 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
332 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
335 EndpointManager m_query,m_idreq;
336 vector<const XMLCh*> m_formats,m_attrprofs;
337 vector<const SAMLAttribute*> m_attrs;
340 class EntityDescriptor : public IEntityDescriptor
345 XMLMetadataImpl* wrapper,
346 time_t validUntil=LONG_MAX,
347 const IEntitiesDescriptor* parent=NULL
352 const XMLCh* getId() const {return m_id;}
353 bool isValid() const {return time(NULL) < m_validUntil;}
354 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
355 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
356 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
357 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
358 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
359 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
360 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
361 const IOrganization* getOrganization() const {return m_org;}
362 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
363 saml::Iterator<std::pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
364 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
365 const DOMElement* getElement() const {return m_root;}
368 const char* getErrorURL() const {return m_errorURL.get();}
369 time_t getValidUntil() const {return m_validUntil;}
371 const DOMElement* m_root;
372 const IEntitiesDescriptor* m_parent;
374 auto_ptr<char> m_errorURL;
375 IOrganization* m_org;
376 vector<const IContactPerson*> m_contacts;
377 vector<const IRoleDescriptor*> m_roles;
378 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
382 class EntitiesDescriptor : public IEntitiesDescriptor
387 XMLMetadataImpl* wrapper,
388 time_t validUntil=LONG_MAX,
389 const IEntitiesDescriptor* parent=NULL
391 ~EntitiesDescriptor();
393 const XMLCh* getName() const {return m_name;}
394 bool isValid() const {return time(NULL) < m_validUntil;}
395 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
396 saml::Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
397 saml::Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
398 const DOMElement* getElement() const {return m_root;}
401 const DOMElement* m_root;
402 const IEntitiesDescriptor* m_parent;
404 vector<const IEntitiesDescriptor*> m_groups;
405 vector<const IEntityDescriptor*> m_providers;
409 XMLMetadataImpl(const char* pathname) : ReloadableXMLFileImpl(pathname), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
410 XMLMetadataImpl(const DOMElement* e) : ReloadableXMLFileImpl(e), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
415 typedef multimap<xstring,const EntityDescriptor*> sitemap_t;
417 typedef multimap<string,const EntityDescriptor*> sitemap_t;
420 EntityDescriptor* m_rootProvider;
421 EntitiesDescriptor* m_rootGroup;
424 class XMLMetadata : public IMetadata, public ReloadableXMLFile
427 XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e) {}
430 const IEntityDescriptor* lookup(const XMLCh* providerId) const;
433 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
434 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
438 IPlugIn* XMLMetadataFactory(const DOMElement* e)
440 XMLMetadata* m=new XMLMetadata(e);
442 m->getImplementation();
451 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
453 return new XMLMetadataImpl(e);
456 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
458 return new XMLMetadataImpl(pathname);
461 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
463 const XMLCh* type=NULL;
465 // Old metadata or new?
466 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
467 type=e->getAttributeNS(NULL,SHIB_L(Type));
468 m_surName=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
469 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
470 auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
472 m_emails.push_back(temp.get());
475 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
476 type=e->getAttributeNS(NULL,SHIB_L(contactType));
478 e=saml::XML::getFirstChildElement(e);
480 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company))) {
481 n=e->getFirstChild();
482 if (n) m_company=auto_ptr<char>(toUTF8(n->getNodeValue()));
484 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName))) {
485 n=e->getFirstChild();
486 if (n) m_givenName=auto_ptr<char>(toUTF8(n->getNodeValue()));
488 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName))) {
489 n=e->getFirstChild();
490 if (n) m_surName=auto_ptr<char>(toUTF8(n->getNodeValue()));
492 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress))) {
493 n=e->getFirstChild();
495 auto_ptr<char> temp(toUTF8(n->getNodeValue()));
496 if (temp.get()) m_emails.push_back(temp.get());
499 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber))) {
500 n=e->getFirstChild();
502 auto_ptr<char> temp(toUTF8(n->getNodeValue()));
503 if (temp.get()) m_phones.push_back(temp.get());
506 e=saml::XML::getNextSiblingElement(e);
510 if (!XMLString::compareString(type,SHIB_L(technical)))
511 m_type=IContactPerson::technical;
512 else if (!XMLString::compareString(type,SHIB_L(support)))
513 m_type=IContactPerson::support;
514 else if (!XMLString::compareString(type,SHIB_L(administrative)))
515 m_type=IContactPerson::administrative;
516 else if (!XMLString::compareString(type,SHIB_L(billing)))
517 m_type=IContactPerson::billing;
518 else if (!XMLString::compareString(type,SHIB_L(other)))
519 m_type=IContactPerson::other;
522 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
525 e=saml::XML::getFirstChildElement(e);
527 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
528 n=e->getFirstChild();
530 auto_ptr<char> name(toUTF8(n->getNodeValue()));
531 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
532 m_names[lang.get()]=name.get();
535 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
536 n=e->getFirstChild();
538 auto_ptr<char> display(toUTF8(n->getNodeValue()));
539 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
540 m_displays[lang.get()]=display.get();
543 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
544 n=e->getFirstChild();
546 auto_ptr<char> url(toUTF8(n->getNodeValue()));
547 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
548 m_urls[lang.get()]=url.get();
551 e=saml::XML::getNextSiblingElement(e);
555 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
557 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
558 e=saml::XML::getFirstChildElement(e);
559 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
560 DOMNode* n=e->getFirstChild();
561 if (n) m_size=XMLString::parseInt(n->getNodeValue());
563 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
564 DOMNode* n=e->getFirstChild();
565 if (n) m_digest=n->getNodeValue();
567 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
568 DOMNode* n=e->getFirstChild();
569 if (n) m_params=n->getNodeValue();
573 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
575 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
577 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
580 // Process ds:KeyInfo
581 e=saml::XML::getFirstChildElement(e);
583 // We let XMLSec hack through anything it can. This should evolve over time, or we can
584 // plug in our own KeyResolver later...
585 DOMElement* child=saml::XML::getFirstChildElement(e);
588 if (!m_klist.addXMLKeyInfo(child)) {
589 Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl.KeyDescriptor").warn(
590 "skipped unsupported ds:KeyInfo child element");
593 catch (XSECCryptoException& xe) {
594 Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl.KeyDescriptor").error(
595 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
597 child=saml::XML::getNextSiblingElement(child);
600 // Check for encryption methods.
601 e=saml::XML::getNextSiblingElement(e);
602 while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
603 m_methods.push_back(new EncryptionMethod(e));
606 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
608 for (vector<const XENCEncryptionMethod*>::iterator i=m_methods.begin(); i!=m_methods.end(); i++)
609 delete const_cast<XENCEncryptionMethod*>(*i);
612 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
613 : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
615 // Check the root element namespace. If SAML2, assume it's the std schema.
616 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
618 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
619 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
621 m_validUntil=min(m_validUntil,exp.getEpoch());
624 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
625 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
627 // Chop the protocol list into pieces...assume any whitespace can appear in between.
628 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
629 XMLCh* temp=m_protocolEnumCopy;
630 while (temp && *temp) {
632 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
634 m_protocolEnum.push_back(start);
636 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
639 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
641 m_keys.push_back(new KeyDescriptor(e));
642 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
645 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
647 m_org=new Organization(e);
649 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
651 m_contacts.push_back(new ContactPerson(e));
652 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
657 XMLMetadataImpl::Role::~Role()
661 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
662 for (vector<const IKeyDescriptor*>::iterator i=m_keys.begin(); i!=m_keys.end(); i++)
663 delete const_cast<IKeyDescriptor*>(*i);
664 for (vector<const IContactPerson*>::iterator j=m_contacts.begin(); j!=m_contacts.end(); j++)
665 delete const_cast<IContactPerson*>(*j);
668 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
670 Iterator<const XMLCh*> i(m_protocolEnum);
671 while (i.hasNext()) {
672 if (!XMLString::compareString(protocol,i.next()))
678 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
679 : Role(provider,validUntil,e)
681 // Check the root element namespace. If SAML2, assume it's the std schema.
682 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
684 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
685 for (i=0; nlist && i<nlist->getLength(); i++)
686 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
688 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
689 for (i=0; nlist && i<nlist->getLength(); i++)
690 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
692 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
693 for (i=0; nlist && i<nlist->getLength(); i++)
694 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
696 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
697 for (i=0; nlist && i<nlist->getLength(); i++) {
698 DOMNode* n=nlist->item(i)->getFirstChild();
699 if (n) m_formats.push_back(n->getNodeValue());
703 // For old style, we just do SAML 1.1 compatibility with Shib handles.
704 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
705 m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
709 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
711 // Check the root element namespace. If SAML2, assume it's the std schema.
712 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS))
713 e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
716 e=saml::XML::getFirstChildElement(e,::XML::SHIB_NS,SHIB_L(Domain));
718 const XMLCh* dom=(e->getFirstChild()) ? e->getFirstChild()->getNodeValue() : NULL;
720 const XMLCh* regexp=e->getAttributeNS(NULL,SHIB_L(regexp));
722 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
725 e=saml::XML::getNextSiblingElement(e,::XML::SHIB_NS,SHIB_L(Domain));
730 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
731 : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false)
733 // Check the root element namespace. If SAML2, assume it's the std schema.
734 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
735 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
736 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
739 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
740 for (i=0; nlist && i<nlist->getLength(); i++)
741 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
743 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
744 for (i=0; nlist && i<nlist->getLength(); i++)
745 m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
747 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
748 for (i=0; nlist && i<nlist->getLength(); i++)
749 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
751 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
752 for (i=0; nlist && i<nlist->getLength(); i++) {
753 DOMNode* n=nlist->item(i)->getFirstChild();
754 if (n) m_attrprofs.push_back(n->getNodeValue());
757 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
758 for (i=0; nlist && i<nlist->getLength(); i++) {
759 // For now, we need to convert these to plain SAML 1.1 attributes.
760 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
761 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
762 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
763 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
764 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
766 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
767 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
768 DOMNamedNodeMap* attrs = src->getAttributes();
769 for (int j=0; j<attrs->getLength(); j++)
770 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
771 while (src->hasChildNodes())
772 val->appendChild(src->getFirstChild());
773 copy->appendChild(val);
775 m_attrs.push_back(SAMLAttribute::getInstance(copy));
779 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
781 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
782 for (i=0; nlist && i<nlist->getLength(); i++) {
783 // Manufacture an endpoint for the "Shib" binding.
785 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Location)))
788 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
789 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
790 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
791 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
793 e->getOwnerDocument()->createTextNode(
794 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
799 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
800 m_keys.push_back(new KeyDescriptor(kd));
805 XMLMetadataImpl::IDPRole::~IDPRole()
807 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
808 delete const_cast<SAMLAttribute*>(*i);
811 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
812 : Role(provider,validUntil,e), ScopedRole(e)
814 // Check the root element namespace. If SAML2, assume it's the std schema.
815 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
817 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
818 for (i=0; nlist && i<nlist->getLength(); i++)
819 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
821 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
822 for (i=0; nlist && i<nlist->getLength(); i++)
823 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
825 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
826 for (i=0; nlist && i<nlist->getLength(); i++) {
827 DOMNode* n=nlist->item(i)->getFirstChild();
828 if (n) m_formats.push_back(n->getNodeValue());
831 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
832 for (i=0; nlist && i<nlist->getLength(); i++) {
833 DOMNode* n=nlist->item(i)->getFirstChild();
834 if (n) m_attrprofs.push_back(n->getNodeValue());
837 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
838 for (i=0; nlist && i<nlist->getLength(); i++) {
839 // For now, we need to convert these to plain SAML 1.1 attributes.
840 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
841 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
842 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
843 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
844 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
846 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
847 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
848 DOMNamedNodeMap* attrs = src->getAttributes();
849 for (int j=0; j<attrs->getLength(); j++)
850 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
851 while (src->hasChildNodes())
852 val->appendChild(src->getFirstChild());
853 copy->appendChild(val);
855 m_attrs.push_back(SAMLAttribute::getInstance(copy));
859 // For old style, we just do SAML 1.1 compatibility with Shib handles.
860 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
861 m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
862 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
864 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
865 for (i=0; nlist && i<nlist->getLength(); i++) {
866 // Manufacture an endpoint for the SOAP binding.
869 SAMLBinding::SAML_SOAP_HTTPS,
870 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Location))
874 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
875 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
876 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
877 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
879 e->getOwnerDocument()->createTextNode(
880 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
885 m_keys.push_back(new KeyDescriptor(kd));
890 XMLMetadataImpl::AARole::~AARole()
892 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
893 delete const_cast<SAMLAttribute*>(*i);
896 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
897 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
898 ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
900 // Check the root element namespace. If SAML2, assume it's the std schema.
901 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
902 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
904 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
905 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
907 m_validUntil=min(validUntil,exp.getEpoch());
910 DOMElement* child=saml::XML::getFirstChildElement(e);
912 // Process the various kinds of children that we care about...
913 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
914 m_contacts.push_back(new ContactPerson(child));
916 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
917 m_org=new Organization(child);
919 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
920 DOMNode* loc=child->getFirstChild();
923 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
926 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
927 m_roles.push_back(new IDPRole(this,m_validUntil,child));
929 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
930 m_roles.push_back(new AARole(this,m_validUntil,child));
932 child = saml::XML::getNextSiblingElement(child);
936 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
937 m_errorURL=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
939 bool idp=false,aa=false; // only want to build a role once
940 DOMElement* child=saml::XML::getFirstChildElement(e);
942 // Process the various kinds of OriginSite children that we care about...
943 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
944 m_contacts.push_back(new ContactPerson(child));
946 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
947 // Create the IDP role if needed.
948 m_roles.push_back(new IDPRole(this, m_validUntil, e));
951 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
952 // Create the AA role if needed.
953 m_roles.push_back(new AARole(this, m_validUntil, e));
956 child = saml::XML::getNextSiblingElement(child);
960 wrapper->m_sites.insert(pair<xstring,const EntityDescriptor*>(m_id,this));
962 auto_ptr_char id(m_id);
963 wrapper->m_sites.insert(pair<string,const EntityDescriptor*>(id.get(),this));
967 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
969 const IIDPSSODescriptor* ret=NULL;
970 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
971 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
977 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
979 const IAttributeAuthorityDescriptor* ret=NULL;
980 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
981 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
987 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
990 for (vector<const IContactPerson*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
991 delete const_cast<IContactPerson*>(*i);
992 for (vector<const IRoleDescriptor*>::iterator j=m_roles.begin(); j!=m_roles.end(); j++)
993 delete const_cast<IRoleDescriptor*>(*j);
996 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
997 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
998 ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1000 // Check the root element namespace. If SAML2, assume it's the std schema.
1001 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1003 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1004 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1005 exp.parseDateTime();
1006 m_validUntil=min(validUntil,exp.getEpoch());
1009 e=saml::XML::getFirstChildElement(e);
1011 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor)))
1012 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1013 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor)))
1014 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1015 e=saml::XML::getNextSiblingElement(e);
1019 e=saml::XML::getFirstChildElement(e);
1021 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup)))
1022 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1023 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1024 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1025 e=saml::XML::getNextSiblingElement(e);
1030 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1032 for (vector<const IEntityDescriptor*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
1033 delete const_cast<IEntityDescriptor*>(*i);
1034 for (vector<const IEntitiesDescriptor*>::iterator j=m_groups.begin(); j!=m_groups.end(); j++)
1035 delete const_cast<IEntitiesDescriptor*>(*j);
1038 void XMLMetadataImpl::init()
1040 NDC ndc("XMLMetadataImpl");
1041 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".XMLMetadataImpl");
1045 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor)))
1046 m_rootGroup=new EntitiesDescriptor(m_root,this);
1047 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor)))
1048 m_rootProvider=new EntityDescriptor(m_root,this);
1049 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup)))
1050 m_rootGroup=new EntitiesDescriptor(m_root,this);
1051 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite)))
1052 m_rootProvider=new EntityDescriptor(m_root,this);
1054 log.error("Construction requires a valid SAML metadata file");
1055 throw MetadataException("Construction requires a valid SAML metadata file");
1058 catch (SAMLException& e)
1060 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1061 this->~XMLMetadataImpl();
1066 log.error("Unexpected error while parsing SAML metadata");
1067 this->~XMLMetadataImpl();
1072 XMLMetadataImpl::~XMLMetadataImpl()
1075 delete m_rootProvider;
1078 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId) const
1080 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1081 #ifdef HAVE_GOOD_STL
1082 pair<XMLMetadataImpl::sitemap_t::const_iterator,XMLMetadataImpl::sitemap_t::const_iterator> range=
1083 impl->m_sites.equal_range(providerId);
1085 auto_ptr_char temp(providerId);
1086 pair<XMLMetadataImpl::sitemap_t::const_iterator,XMLMetadataImpl::sitemap_t::const_iterator> range=
1087 impl->m_sites.equal_range(temp.get());
1089 time_t now=time(NULL);
1090 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1091 if (now < i->second->getValidUntil())