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/dsig/DSIGTransformC14n.hpp>
66 #include <xsec/dsig/DSIGReference.hpp>
67 #include <xsec/dsig/DSIGTransformList.hpp>
68 #include <xsec/enc/XSECCryptoException.hpp>
69 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
70 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
71 #include <xsec/framework/XSECException.hpp>
72 #include <xsec/framework/XSECProvider.hpp>
74 using namespace shibboleth;
76 using namespace log4cpp;
82 class XMLMetadataImpl : public ReloadableXMLFileImpl
85 class ContactPerson : public IContactPerson
88 ContactPerson(const DOMElement* e);
91 ContactType getType() const { return m_type; }
92 const char* getCompany() const { return m_company.get(); }
93 const char* getGivenName() const { return m_givenName.get(); }
94 const char* getSurName() const { return m_surName.get(); }
95 Iterator<string> getEmailAddresses() const { return m_emails; }
96 Iterator<string> getTelephoneNumbers() const { return m_phones; }
97 const DOMElement* getElement() const { return m_root; }
100 const DOMElement* m_root;
102 auto_ptr<char> m_givenName,m_surName,m_company;
103 vector<string> m_emails,m_phones;
106 class Organization : public IOrganization
109 Organization(const DOMElement* e);
112 const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
113 const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
114 const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
115 const DOMElement* getElement() const { return m_root; }
118 const char* forLang(const map<string,string>& m, const char* lang) const {
119 map<string,string>::const_iterator i=m.find(lang);
120 return (i==m.end()) ? NULL : i->second.c_str();
122 const DOMElement* m_root;
123 map<string,string> m_names,m_displays,m_urls;
126 class EntityDescriptor;
128 class EncryptionMethod : public XENCEncryptionMethod
131 EncryptionMethod(const DOMElement* e);
132 ~EncryptionMethod() {}
134 const XMLCh * getAlgorithm(void) const { return m_alg; }
135 const XMLCh * getDigestMethod(void) const { return m_digest; }
136 const XMLCh * getOAEPparams(void) const { return m_params; }
137 int getKeySize(void) const { return m_size; }
138 DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
139 void setDigestMethod(const XMLCh * method) {throw exception();}
140 void setOAEPparams(const XMLCh * params) {throw exception();}
141 void setKeySize(int size) {throw exception();}
144 const DOMElement* m_root;
146 const XMLCh* m_digest;
147 const XMLCh* m_params;
151 class KeyDescriptor : public IKeyDescriptor
154 KeyDescriptor(const DOMElement* e);
157 KeyUse getUse() const { return m_use; }
158 DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
159 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
160 const DOMElement* getElement() const { return m_root; }
163 const DOMElement* m_root;
165 mutable DSIGKeyInfoList* m_klist;
166 vector<const XENCEncryptionMethod*> m_methods;
169 class KeyAuthority : public IKeyAuthority
172 KeyAuthority(const DOMElement* e);
175 int getVerifyDepth() const { return m_depth; }
176 Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
180 vector<DSIGKeyInfoList*> m_klists;
183 class Role : public virtual IRoleDescriptor
186 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
190 const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
191 Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
192 bool hasSupport(const XMLCh* protocol) const;
193 const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
194 bool isValid() const {return time(NULL) < m_validUntil;}
195 Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
196 const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
197 Iterator<const IContactPerson*> getContactPersons() const
198 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
199 const DOMElement* getElement() const {return m_root;}
202 vector<const XMLCh*> m_protocolEnum;
203 vector<const IKeyDescriptor*> m_keys;
206 const EntityDescriptor* m_provider;
207 const DOMElement* m_root;
208 XMLCh* m_protocolEnumCopy;
211 vector<const IContactPerson*> m_contacts;
215 class Endpoint : public virtual IEndpoint
218 Endpoint(const DOMElement* e) : m_root(e),
219 m_binding(e->getAttributeNS(NULL,L(Binding))),
220 m_location(e->getAttributeNS(NULL,L(Location))),
221 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
222 Endpoint(const XMLCh* binding, const XMLCh* loc)
223 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
226 const XMLCh* getBinding() const { return m_binding; }
227 const XMLCh* getLocation() const { return m_location; }
228 const XMLCh* getResponseLocation() const { return m_resploc; }
229 const DOMElement* getElement() const { return m_root; }
232 const DOMElement* m_root;
233 const XMLCh* m_binding;
234 const XMLCh* m_location;
235 const XMLCh* m_resploc;
238 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
241 IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
242 unsigned short getIndex() const {return m_index;}
245 unsigned short m_index;
248 class EndpointManager : public IEndpointManager
251 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
253 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
254 delete const_cast<IEndpoint*>(*i);
256 saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
257 const IEndpoint* getDefaultEndpoint() const {
258 if (m_hard) return m_hard;
259 if (m_soft) return m_soft;
260 if (!m_endpoints.empty()) return *(m_endpoints.begin());
263 const IEndpoint* getEndpointByIndex(unsigned short index) const {
264 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
265 const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
266 if (temp && index==temp->getIndex())
271 const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
272 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
273 if (!XMLString::compareString(binding,(*i)->getBinding()))
277 void add(IEndpoint* e) {
278 m_endpoints.push_back(e);
279 if (!m_hard && e->getElement()) {
280 const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
281 if (v && (*v==chDigit_1 || *v==chLatin_t)) // explicit default
283 else if ((!v || !*v) && !m_soft) // implicit default
286 else if (!m_hard && !m_soft) {
287 // No default yet, so this one qualifies as an implicit.
293 vector<const IEndpoint*> m_endpoints;
294 const IEndpoint* m_soft; // Soft default (not explicit)
295 const IEndpoint* m_hard; // Hard default (explicit)
298 class SSORole : public Role, public virtual ISSODescriptor
301 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
303 const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
304 const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
305 const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
306 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
309 EndpointManager m_artifact,m_logout,m_nameid;
310 vector<const XMLCh*> m_formats;
313 class ScopedRole : public virtual IScopedRoleDescriptor
316 ScopedRole(const DOMElement* e);
317 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
320 vector<pair<const XMLCh*,bool> > m_scopes;
323 class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
326 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
328 bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
329 const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
330 const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
331 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
332 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
333 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
336 EndpointManager m_sso,m_mapping,m_idreq;
337 vector<const XMLCh*> m_attrprofs;
338 vector<const SAMLAttribute*> m_attrs;
339 bool m_wantAuthnRequestsSigned;
340 const XMLCh* m_sourceId;
341 friend class EntityDescriptor;
344 class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
347 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
349 const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
350 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
351 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
352 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
353 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
356 EndpointManager m_query,m_idreq;
357 vector<const XMLCh*> m_formats,m_attrprofs;
358 vector<const SAMLAttribute*> m_attrs;
361 class EntityDescriptor : public IExtendedEntityDescriptor
366 XMLMetadataImpl* wrapper,
367 time_t validUntil=LONG_MAX,
368 const IEntitiesDescriptor* parent=NULL
373 const XMLCh* getId() const {return m_id;}
374 bool isValid() const {return time(NULL) < m_validUntil;}
375 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
376 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
377 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
378 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
379 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
380 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
381 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
382 const IOrganization* getOrganization() const {return m_org;}
383 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
384 Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
385 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
386 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
387 const DOMElement* getElement() const {return m_root;}
390 const char* getErrorURL() const {return m_errorURL.get();}
391 time_t getValidUntil() const {return m_validUntil;}
393 const DOMElement* m_root;
394 const IEntitiesDescriptor* m_parent;
396 auto_ptr<char> m_errorURL;
397 IOrganization* m_org;
398 vector<const IContactPerson*> m_contacts;
399 vector<const IRoleDescriptor*> m_roles;
400 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
401 vector<const IKeyAuthority*> m_keyauths;
405 class EntitiesDescriptor : public IExtendedEntitiesDescriptor
410 XMLMetadataImpl* wrapper,
411 time_t validUntil=LONG_MAX,
412 const IEntitiesDescriptor* parent=NULL
414 ~EntitiesDescriptor();
416 const XMLCh* getName() const {return m_name;}
417 bool isValid() const {return time(NULL) < m_validUntil;}
418 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
419 Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
420 Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
421 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
422 const DOMElement* getElement() const {return m_root;}
425 time_t getValidUntil() const {return m_validUntil;}
427 const DOMElement* m_root;
428 const IEntitiesDescriptor* m_parent;
430 vector<const IEntitiesDescriptor*> m_groups;
431 vector<const IEntityDescriptor*> m_providers;
432 vector<const IKeyAuthority*> m_keyauths;
436 XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
437 : ReloadableXMLFileImpl(pathname), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
438 XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
439 : ReloadableXMLFileImpl(e), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
443 typedef multimap<string,const EntityDescriptor*> sitemap_t;
444 typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
448 EntityDescriptor* m_rootProvider;
449 EntitiesDescriptor* m_rootGroup;
450 const XMLMetadata* m_outer;
453 class XMLMetadata : public IMetadata, public ReloadableXMLFile
456 XMLMetadata(const DOMElement* e);
457 ~XMLMetadata() {delete m_credResolver;}
459 const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
460 const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
461 const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
462 const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
463 const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
464 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
466 bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
469 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
470 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
473 bool m_exclusions,m_verify;
475 ICredResolver* m_credResolver;
479 IPlugIn* XMLMetadataFactory(const DOMElement* e)
481 auto_ptr<XMLMetadata> m(new XMLMetadata(e));
482 m->getImplementation();
486 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
488 return new XMLMetadataImpl(e,this);
491 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
493 return new XMLMetadataImpl(pathname,this);
496 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
498 const XMLCh* type=NULL;
500 // Old metadata or new?
501 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
502 type=e->getAttributeNS(NULL,SHIB_L(Type));
503 m_surName=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
504 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
505 auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
507 m_emails.push_back(temp.get());
510 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
511 type=e->getAttributeNS(NULL,SHIB_L(contactType));
513 e=saml::XML::getFirstChildElement(e);
515 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company))) {
516 n=e->getFirstChild();
517 if (n) m_company=auto_ptr<char>(toUTF8(n->getNodeValue()));
519 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName))) {
520 n=e->getFirstChild();
521 if (n) m_givenName=auto_ptr<char>(toUTF8(n->getNodeValue()));
523 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName))) {
524 n=e->getFirstChild();
525 if (n) m_surName=auto_ptr<char>(toUTF8(n->getNodeValue()));
527 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress))) {
528 n=e->getFirstChild();
530 auto_ptr<char> temp(toUTF8(n->getNodeValue()));
531 if (temp.get()) m_emails.push_back(temp.get());
534 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber))) {
535 n=e->getFirstChild();
537 auto_ptr<char> temp(toUTF8(n->getNodeValue()));
538 if (temp.get()) m_phones.push_back(temp.get());
541 e=saml::XML::getNextSiblingElement(e);
545 if (!XMLString::compareString(type,SHIB_L(technical)))
546 m_type=IContactPerson::technical;
547 else if (!XMLString::compareString(type,SHIB_L(support)))
548 m_type=IContactPerson::support;
549 else if (!XMLString::compareString(type,SHIB_L(administrative)))
550 m_type=IContactPerson::administrative;
551 else if (!XMLString::compareString(type,SHIB_L(billing)))
552 m_type=IContactPerson::billing;
553 else if (!XMLString::compareString(type,SHIB_L(other)))
554 m_type=IContactPerson::other;
557 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
560 e=saml::XML::getFirstChildElement(e);
562 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
563 n=e->getFirstChild();
565 auto_ptr<char> name(toUTF8(n->getNodeValue()));
566 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
567 m_names[lang.get()]=name.get();
570 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
571 n=e->getFirstChild();
573 auto_ptr<char> display(toUTF8(n->getNodeValue()));
574 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
575 m_displays[lang.get()]=display.get();
578 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
579 n=e->getFirstChild();
581 auto_ptr<char> url(toUTF8(n->getNodeValue()));
582 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
583 m_urls[lang.get()]=url.get();
586 e=saml::XML::getNextSiblingElement(e);
590 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
592 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
593 e=saml::XML::getFirstChildElement(e);
595 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
596 DOMNode* n=e->getFirstChild();
597 if (n) m_size=XMLString::parseInt(n->getNodeValue());
599 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
600 DOMNode* n=e->getFirstChild();
601 if (n) m_digest=n->getNodeValue();
603 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
604 DOMNode* n=e->getFirstChild();
605 if (n) m_params=n->getNodeValue();
607 e=saml::XML::getNextSiblingElement(e);
611 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
614 saml::NDC ndc("KeyDescriptor");
616 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
618 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
621 m_klist = new DSIGKeyInfoList(NULL);
623 // Process ds:KeyInfo
624 e=saml::XML::getFirstChildElement(e);
626 // We let XMLSec hack through anything it can. This should evolve over time, or we can
627 // plug in our own KeyResolver later...
629 if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
630 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
631 "skipping ds:KeyInfo element containing unsupported children"
634 catch (XSECCryptoException& xe) {
635 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
638 // Check for encryption methods.
639 e=saml::XML::getNextSiblingElement(e);
640 while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
641 m_methods.push_back(new EncryptionMethod(e));
644 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
646 for (vector<const XENCEncryptionMethod*>::iterator i=m_methods.begin(); i!=m_methods.end(); i++)
647 delete const_cast<XENCEncryptionMethod*>(*i);
651 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
654 saml::NDC ndc("KeyAuthority");
656 if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
657 m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
659 // Process ds:KeyInfo children
660 e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
662 auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
664 // We let XMLSec hack through anything it can. This should evolve over time, or we can
665 // plug in our own KeyResolver later...
666 DOMElement* child=saml::XML::getFirstChildElement(e);
669 if (!klist->addXMLKeyInfo(child)) {
670 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
671 "skipped unresolvable ds:KeyInfo child element");
674 catch (XSECCryptoException& xe) {
675 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
676 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
678 child=saml::XML::getNextSiblingElement(child);
681 if (klist->getSize()>0)
682 m_klists.push_back(klist.release());
684 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
685 "skipping ds:KeyInfo with no resolvable child elements");
686 e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
690 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
692 for (vector<DSIGKeyInfoList*>::iterator i=m_klists.begin(); i!=m_klists.end(); i++)
696 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
697 : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
699 // Check the root element namespace. If SAML2, assume it's the std schema.
700 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
702 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
703 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
705 m_validUntil=min(m_validUntil,exp.getEpoch());
708 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
709 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
711 // Chop the protocol list into pieces...assume any whitespace can appear in between.
712 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
713 XMLCh* temp=m_protocolEnumCopy;
714 while (temp && *temp) {
716 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
719 m_protocolEnum.push_back(start);
720 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
723 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
725 m_keys.push_back(new KeyDescriptor(e));
726 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
729 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
731 m_org=new Organization(e);
733 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
735 m_contacts.push_back(new ContactPerson(e));
736 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
741 XMLMetadataImpl::Role::~Role()
745 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
746 for (vector<const IKeyDescriptor*>::iterator i=m_keys.begin(); i!=m_keys.end(); i++)
747 delete const_cast<IKeyDescriptor*>(*i);
748 for (vector<const IContactPerson*>::iterator j=m_contacts.begin(); j!=m_contacts.end(); j++)
749 delete const_cast<IContactPerson*>(*j);
752 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
754 Iterator<const XMLCh*> i(m_protocolEnum);
755 while (i.hasNext()) {
756 if (!XMLString::compareString(protocol,i.next()))
762 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
763 : Role(provider,validUntil,e)
765 // Check the root element namespace. If SAML2, assume it's the std schema.
766 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
768 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
769 for (i=0; nlist && i<nlist->getLength(); i++)
770 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
772 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
773 for (i=0; nlist && i<nlist->getLength(); i++)
774 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
776 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
777 for (i=0; nlist && i<nlist->getLength(); i++)
778 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
780 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
781 for (i=0; nlist && i<nlist->getLength(); i++) {
782 DOMNode* n=nlist->item(i)->getFirstChild();
783 if (n) m_formats.push_back(n->getNodeValue());
787 // For old style, we just do SAML 1.1 compatibility with Shib handles.
788 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
789 m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
793 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
795 // Check the root element namespace. If SAML2, assume it's the std schema.
796 DOMNodeList* nlist=NULL;
797 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
798 e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
799 if (e) nlist=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
802 nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
805 for (int i=0; nlist && i < nlist->getLength(); i++) {
806 const XMLCh* dom=(nlist->item(i)->hasChildNodes()) ? nlist->item(i)->getFirstChild()->getNodeValue() : NULL;
808 const XMLCh* regexp=static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
810 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
816 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
817 : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
819 // Check the root element namespace. If SAML2, assume it's the std schema.
820 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
821 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
822 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
824 // Check for SourceID extension.
825 DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
827 ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
828 if (ext && ext->hasChildNodes())
829 m_sourceId=ext->getFirstChild()->getNodeValue();
833 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
834 for (i=0; nlist && i<nlist->getLength(); i++)
835 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
837 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
838 for (i=0; nlist && i<nlist->getLength(); i++)
839 m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
841 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
842 for (i=0; nlist && i<nlist->getLength(); i++)
843 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
845 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
846 for (i=0; nlist && i<nlist->getLength(); i++) {
847 DOMNode* n=nlist->item(i)->getFirstChild();
848 if (n) m_attrprofs.push_back(n->getNodeValue());
851 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
852 for (i=0; nlist && i<nlist->getLength(); i++) {
853 // For now, we need to convert these to plain SAML 1.1 attributes.
854 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
855 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
856 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
857 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
858 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
860 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
861 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
862 DOMNamedNodeMap* attrs = src->getAttributes();
863 for (int j=0; j<attrs->getLength(); j++)
864 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
865 while (src->hasChildNodes())
866 val->appendChild(src->getFirstChild());
867 copy->appendChild(val);
869 m_attrs.push_back(SAMLAttribute::getInstance(copy));
873 m_protocolEnum.push_back(Constants::SHIB_NS);
874 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
876 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
877 for (i=0; nlist && i<nlist->getLength(); i++) {
878 // Manufacture an endpoint for the "Shib" binding.
880 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
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));
888 e->getOwnerDocument()->createTextNode(
889 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
894 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
895 m_keys.push_back(new KeyDescriptor(kd));
900 XMLMetadataImpl::IDPRole::~IDPRole()
902 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
903 delete const_cast<SAMLAttribute*>(*i);
906 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
907 : Role(provider,validUntil,e), ScopedRole(e)
909 // Check the root element namespace. If SAML2, assume it's the std schema.
910 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
912 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
913 for (i=0; nlist && i<nlist->getLength(); i++)
914 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
916 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
917 for (i=0; nlist && i<nlist->getLength(); i++)
918 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
920 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
921 for (i=0; nlist && i<nlist->getLength(); i++) {
922 DOMNode* n=nlist->item(i)->getFirstChild();
923 if (n) m_formats.push_back(n->getNodeValue());
926 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
927 for (i=0; nlist && i<nlist->getLength(); i++) {
928 DOMNode* n=nlist->item(i)->getFirstChild();
929 if (n) m_attrprofs.push_back(n->getNodeValue());
932 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
933 for (i=0; nlist && i<nlist->getLength(); i++) {
934 // For now, we need to convert these to plain SAML 1.1 attributes.
935 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
936 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
937 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
938 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
939 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
941 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
942 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
943 DOMNamedNodeMap* attrs = src->getAttributes();
944 for (int j=0; j<attrs->getLength(); j++)
945 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
946 while (src->hasChildNodes())
947 val->appendChild(src->getFirstChild());
948 copy->appendChild(val);
950 m_attrs.push_back(SAMLAttribute::getInstance(copy));
954 // For old style, we just do SAML 1.1 compatibility with Shib handles.
955 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
956 m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
957 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
959 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
960 for (i=0; nlist && i<nlist->getLength(); i++) {
961 // Manufacture an endpoint for the SOAP binding.
965 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
969 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
970 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
971 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
972 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
974 e->getOwnerDocument()->createTextNode(
975 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
980 m_keys.push_back(new KeyDescriptor(kd));
985 XMLMetadataImpl::AARole::~AARole()
987 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
988 delete const_cast<SAMLAttribute*>(*i);
991 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
992 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
993 ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
995 // Check the root element namespace. If SAML2, assume it's the std schema.
996 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
997 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
999 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1000 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1001 exp.parseDateTime();
1002 m_validUntil=min(validUntil,exp.getEpoch());
1005 DOMElement* child=saml::XML::getFirstChildElement(e);
1007 // Process the various kinds of children that we care about...
1008 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1009 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1011 m_keyauths.push_back(new KeyAuthority(ext));
1012 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1015 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
1016 m_contacts.push_back(new ContactPerson(child));
1018 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
1019 m_org=new Organization(child);
1021 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
1022 DOMNode* loc=child->getFirstChild();
1025 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
1028 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
1029 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
1030 m_roles.push_back(new IDPRole(this,m_validUntil,child));
1032 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
1033 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
1034 m_roles.push_back(new AARole(this,m_validUntil,child));
1036 child = saml::XML::getNextSiblingElement(child);
1040 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
1041 m_errorURL=auto_ptr<char>(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
1043 bool idp=false,aa=false; // only want to build a role once
1044 DOMElement* child=saml::XML::getFirstChildElement(e);
1046 // Process the various kinds of OriginSite children that we care about...
1047 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
1048 m_contacts.push_back(new ContactPerson(child));
1050 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
1051 // Create the IDP role if needed.
1052 m_roles.push_back(new IDPRole(this, m_validUntil, e));
1055 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
1056 // Create the AA role if needed.
1057 m_roles.push_back(new AARole(this, m_validUntil, e));
1060 child = saml::XML::getNextSiblingElement(child);
1064 auto_ptr_char id(m_id);
1065 wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1067 // Look for an IdP role, and register the artifact source ID and endpoints.
1068 const IDPRole* idp=NULL;
1069 for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1070 if (idp=dynamic_cast<const IDPRole*>(*r)) {
1071 if (idp->m_sourceId) {
1072 auto_ptr_char sourceid(idp->m_sourceId);
1073 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1076 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1077 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1079 Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1080 while (locs.hasNext()) {
1081 auto_ptr_char loc(locs.next()->getLocation());
1082 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1088 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1090 const IIDPSSODescriptor* ret=NULL;
1091 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1092 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1098 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1100 const IAttributeAuthorityDescriptor* ret=NULL;
1101 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1102 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1108 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1111 for (vector<const IContactPerson*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
1112 delete const_cast<IContactPerson*>(*i);
1113 for (vector<const IRoleDescriptor*>::iterator j=m_roles.begin(); j!=m_roles.end(); j++)
1114 delete const_cast<IRoleDescriptor*>(*j);
1115 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1116 delete const_cast<IKeyAuthority*>(*k);
1119 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1120 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1121 ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1123 // Check the root element namespace. If SAML2, assume it's the std schema.
1124 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1126 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1127 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1128 exp.parseDateTime();
1129 m_validUntil=min(validUntil,exp.getEpoch());
1132 e=saml::XML::getFirstChildElement(e);
1134 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1135 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1137 m_keyauths.push_back(new KeyAuthority(ext));
1138 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1141 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1142 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1143 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1145 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1146 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1147 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1149 e=saml::XML::getNextSiblingElement(e);
1153 e=saml::XML::getFirstChildElement(e);
1155 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1156 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1157 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1159 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1160 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1161 e=saml::XML::getNextSiblingElement(e);
1165 if (!saml::XML::isEmpty(m_name)) {
1166 auto_ptr_char n(m_name);
1167 wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1173 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1175 for (vector<const IEntityDescriptor*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
1176 delete const_cast<IEntityDescriptor*>(*i);
1177 for (vector<const IEntitiesDescriptor*>::iterator j=m_groups.begin(); j!=m_groups.end(); j++)
1178 delete const_cast<IEntitiesDescriptor*>(*j);
1179 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1180 delete const_cast<IKeyAuthority*>(*k);
1183 void XMLMetadataImpl::init()
1188 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1192 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1193 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1194 m_rootGroup=new EntitiesDescriptor(m_root,this);
1196 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1197 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1198 m_rootProvider=new EntityDescriptor(m_root,this);
1200 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1201 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1202 m_rootGroup=new EntitiesDescriptor(m_root,this);
1204 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1205 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1206 m_rootProvider=new EntityDescriptor(m_root,this);
1209 log.error("Construction requires a valid SAML metadata file");
1210 throw MetadataException("Construction requires a valid SAML metadata file");
1213 catch (SAMLException& e)
1215 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1216 this->~XMLMetadataImpl();
1222 log.error("Unexpected error while parsing SAML metadata");
1223 this->~XMLMetadataImpl();
1228 if (!m_rootGroup && !m_rootProvider) {
1229 log.error("Metadata file contained no valid information");
1230 throw MetadataException("Metadata file contained no valid information");
1234 XMLMetadataImpl::~XMLMetadataImpl()
1237 delete m_rootProvider;
1240 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1242 static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1243 if (e->hasAttributeNS(NULL,uri)) {
1244 // First check for explicit enablement of entities.
1245 DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1246 for (int i=0; nlist && i<nlist->getLength(); i++) {
1247 if (nlist->item(i)->hasChildNodes()) {
1248 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1250 m_set.insert(temp.get());
1255 // If there was no explicit enablement, build a set of exclusions.
1257 nlist=e->getElementsByTagName(SHIB_L(Exclude));
1258 for (int j=0; nlist && j<nlist->getLength(); j++) {
1259 if (nlist->item(j)->hasChildNodes()) {
1260 auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1262 m_set.insert(temp.get());
1268 const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1269 m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1272 DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1274 cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";
1276 r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1278 auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1283 if (!cr_type.empty()) {
1285 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1286 ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1290 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1292 throw UnsupportedExtensionException("plugin was not a credential resolver");
1295 catch (SAMLException& e) {
1296 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1301 if (m_verify && !m_credResolver) {
1302 delete m_credResolver;
1303 throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1307 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1313 saml::NDC ndc("verifySignature");
1315 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1317 DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1320 log.error("rejecting unsigned element");
1326 XSECCryptoX509* cert=NULL;
1327 Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1328 if (certs.hasNext())
1331 log.error("unable to find any certificates to use in verifying signature");
1335 static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1336 static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1338 // Load the signature.
1340 DSIGSignature* sig=NULL;
1342 sig=prov.newSignatureFromDOM(doc,sigNode);
1346 const XMLCh* URI=NULL;
1348 // Verify the signature coverage.
1349 DSIGReferenceList* refs=sig->getReferenceList();
1350 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1351 DSIGReference* ref=refs->item(0);
1354 if (!URI || !*URI || (*URI==chPound &&
1355 !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1356 DSIGTransformList* tlist=ref->getTransforms();
1357 for (int i=0; tlist && i<tlist->getSize(); i++) {
1358 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1360 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1361 tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1371 auto_ptr_char temp((URI && *URI) ? URI : null);
1372 log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1376 sig->setSigningKey(cert->clonePublicKey());
1377 if (!sig->verify()) {
1378 auto_ptr_char temp((URI && *URI) ? URI : null);
1379 log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1383 prov.releaseSignature(sig);
1385 catch(XSECException& e) {
1386 auto_ptr_char msg(e.getMsg());
1387 log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << CategoryStream::ENDLINE;
1389 prov.releaseSignature(sig);
1392 catch(XSECCryptoException& e) {
1393 log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << CategoryStream::ENDLINE;
1395 prov.releaseSignature(sig);
1400 prov.releaseSignature(sig);
1401 log.error("caught unknown exception while verifying metadata signature");
1407 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1409 if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1411 else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1414 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1415 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1416 impl->m_sites.equal_range(providerId);
1418 time_t now=time(NULL);
1419 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1420 if (now < i->second->getValidUntil())
1423 if (!strict && range.first!=range.second)
1424 return range.first->second;
1429 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1431 auto_ptr_char temp(providerId);
1432 return lookup(temp.get(),strict);
1435 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1437 time_t now=time(NULL);
1438 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1439 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1441 // Depends on type of artifact.
1442 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1444 range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1447 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1449 range=impl->m_sources.equal_range(type2->getSourceLocation());
1455 // Check exclude list.
1456 if (range.first!=range.second) {
1457 auto_ptr_char id(range.first->second->getId());
1458 if (m_exclusions && m_set.find(id.get())!=m_set.end())
1460 else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1463 for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1464 if (now < i->second->getValidUntil())
1471 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1473 if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1475 else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1478 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1479 pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1480 impl->m_groups.equal_range(name);
1482 time_t now=time(NULL);
1483 for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1484 if (now < i->second->getValidUntil())
1487 if (!strict && range.first!=range.second)
1488 return range.first->second;
1493 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1495 auto_ptr_char temp(name);
1496 return lookupGroup(temp.get(),strict);
1499 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1501 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1502 return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);