2 * Copyright 2001-2005 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 /* XMLMetadata.cpp - a metadata implementation that uses an XML-based registry
28 #include <sys/types.h>
31 #include <xercesc/util/XMLChar.hpp>
32 #include <xsec/dsig/DSIGTransformC14n.hpp>
33 #include <xsec/dsig/DSIGReference.hpp>
34 #include <xsec/dsig/DSIGTransformList.hpp>
35 #include <xsec/enc/XSECCryptoException.hpp>
36 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
37 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
38 #include <xsec/framework/XSECException.hpp>
39 #include <xsec/framework/XSECProvider.hpp>
41 using namespace xmlproviders::logging;
42 using namespace shibboleth;
49 class XMLMetadataImpl : public ReloadableXMLFileImpl
52 class ContactPerson : public IContactPerson
55 ContactPerson(const DOMElement* e);
62 ContactType getType() const { return m_type; }
63 const char* getCompany() const { return m_company; }
64 const char* getGivenName() const { return m_givenName; }
65 const char* getSurName() const { return m_surName; }
66 Iterator<string> getEmailAddresses() const { return m_emails; }
67 Iterator<string> getTelephoneNumbers() const { return m_phones; }
68 const DOMElement* getElement() const { return m_root; }
71 const DOMElement* m_root;
76 vector<string> m_emails,m_phones;
79 class Organization : public IOrganization
82 Organization(const DOMElement* e);
85 const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
86 const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
87 const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
88 const DOMElement* getElement() const { return m_root; }
91 const char* forLang(const map<string,string>& m, const char* lang) const {
92 map<string,string>::const_iterator i=m.find(lang);
93 return (i==m.end()) ? NULL : i->second.c_str();
95 const DOMElement* m_root;
96 map<string,string> m_names,m_displays,m_urls;
99 class EntityDescriptor;
101 class EncryptionMethod : public XENCEncryptionMethod
104 EncryptionMethod(const DOMElement* e);
105 ~EncryptionMethod() {}
107 const XMLCh * getAlgorithm(void) const { return m_alg; }
108 const XMLCh * getDigestMethod(void) const { return m_digest; }
109 const XMLCh * getOAEPparams(void) const { return m_params; }
110 int getKeySize(void) const { return m_size; }
111 DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
112 void setDigestMethod(const XMLCh * method) {throw exception();}
113 void setOAEPparams(const XMLCh * params) {throw exception();}
114 void setKeySize(int size) {throw exception();}
117 const DOMElement* m_root;
119 const XMLCh* m_digest;
120 const XMLCh* m_params;
124 class KeyDescriptor : public IKeyDescriptor
127 KeyDescriptor(const DOMElement* e);
130 KeyUse getUse() const { return m_use; }
131 DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
132 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
133 const DOMElement* getElement() const { return m_root; }
136 const DOMElement* m_root;
138 mutable DSIGKeyInfoList* m_klist;
139 vector<const XENCEncryptionMethod*> m_methods;
142 class KeyAuthority : public IKeyAuthority
145 KeyAuthority(const DOMElement* e);
148 int getVerifyDepth() const { return m_depth; }
149 Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
153 vector<DSIGKeyInfoList*> m_klists;
156 class Role : public virtual IRoleDescriptor
159 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
163 const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
164 Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
165 bool hasSupport(const XMLCh* protocol) const;
166 const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
167 bool isValid() const {return time(NULL) < m_validUntil;}
168 Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
169 const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
170 Iterator<const IContactPerson*> getContactPersons() const
171 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
172 const DOMElement* getElement() const {return m_root;}
175 vector<const XMLCh*> m_protocolEnum;
176 vector<const IKeyDescriptor*> m_keys;
179 const EntityDescriptor* m_provider;
180 const DOMElement* m_root;
181 XMLCh* m_protocolEnumCopy;
184 vector<const IContactPerson*> m_contacts;
188 class Endpoint : public virtual IEndpoint
191 Endpoint(const DOMElement* e) : m_root(e),
192 m_binding(e->getAttributeNS(NULL,L(Binding))),
193 m_location(e->getAttributeNS(NULL,L(Location))),
194 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
195 Endpoint(const XMLCh* binding, const XMLCh* loc)
196 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
199 const XMLCh* getBinding() const { return m_binding; }
200 const XMLCh* getLocation() const { return m_location; }
201 const XMLCh* getResponseLocation() const { return m_resploc; }
202 const DOMElement* getElement() const { return m_root; }
205 const DOMElement* m_root;
206 const XMLCh* m_binding;
207 const XMLCh* m_location;
208 const XMLCh* m_resploc;
211 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
214 IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
215 unsigned short getIndex() const {return m_index;}
218 unsigned short m_index;
221 class EndpointManager : public IEndpointManager
224 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
226 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
227 delete const_cast<IEndpoint*>(*i);
229 saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
230 const IEndpoint* getDefaultEndpoint() const {
231 if (m_hard) return m_hard;
232 if (m_soft) return m_soft;
233 if (!m_endpoints.empty()) return *(m_endpoints.begin());
236 const IEndpoint* getEndpointByIndex(unsigned short index) const {
237 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
238 const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
239 if (temp && index==temp->getIndex())
244 const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
245 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
246 if (!XMLString::compareString(binding,(*i)->getBinding()))
250 void add(IEndpoint* e) {
251 m_endpoints.push_back(e);
252 if (!m_hard && e->getElement()) {
253 const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
254 if (v && (*v==chDigit_1 || *v==chLatin_t)) // explicit default
256 else if ((!v || !*v) && !m_soft) // implicit default
259 else if (!m_hard && !m_soft) {
260 // No default yet, so this one qualifies as an implicit.
266 vector<const IEndpoint*> m_endpoints;
267 const IEndpoint* m_soft; // Soft default (not explicit)
268 const IEndpoint* m_hard; // Hard default (explicit)
271 class SSORole : public Role, public virtual ISSODescriptor
274 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
276 const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
277 const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
278 const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
279 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
282 EndpointManager m_artifact,m_logout,m_nameid;
283 vector<const XMLCh*> m_formats;
286 class ScopedRole : public virtual IScopedRoleDescriptor
289 ScopedRole(const DOMElement* e);
290 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
293 vector<pair<const XMLCh*,bool> > m_scopes;
296 class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
299 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
301 bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
302 const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
303 const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
304 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
305 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
306 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
309 EndpointManager m_sso,m_mapping,m_idreq;
310 vector<const XMLCh*> m_attrprofs;
311 vector<const SAMLAttribute*> m_attrs;
312 bool m_wantAuthnRequestsSigned;
313 const XMLCh* m_sourceId;
314 friend class EntityDescriptor;
317 class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
320 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
322 const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
323 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
324 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
325 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
326 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
329 EndpointManager m_query,m_idreq;
330 vector<const XMLCh*> m_formats,m_attrprofs;
331 vector<const SAMLAttribute*> m_attrs;
334 class EntityDescriptor : public IExtendedEntityDescriptor
339 XMLMetadataImpl* wrapper,
340 time_t validUntil=LONG_MAX,
341 const IEntitiesDescriptor* parent=NULL
346 const XMLCh* getId() const {return m_id;}
347 bool isValid() const {return time(NULL) < m_validUntil;}
348 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
349 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
350 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
351 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
352 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
353 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
354 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
355 const IOrganization* getOrganization() const {return m_org;}
356 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
357 Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
358 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
359 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
360 const DOMElement* getElement() const {return m_root;}
363 const char* getErrorURL() const {return m_errorURL;}
364 time_t getValidUntil() const {return m_validUntil;}
366 const DOMElement* m_root;
367 const IEntitiesDescriptor* m_parent;
370 IOrganization* m_org;
371 vector<const IContactPerson*> m_contacts;
372 vector<const IRoleDescriptor*> m_roles;
373 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
374 vector<const IKeyAuthority*> m_keyauths;
378 class EntitiesDescriptor : public IExtendedEntitiesDescriptor
383 XMLMetadataImpl* wrapper,
384 time_t validUntil=LONG_MAX,
385 const IEntitiesDescriptor* parent=NULL
387 ~EntitiesDescriptor();
389 const XMLCh* getName() const {return m_name;}
390 bool isValid() const {return time(NULL) < m_validUntil;}
391 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
392 Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
393 Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
394 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
395 const DOMElement* getElement() const {return m_root;}
398 time_t getValidUntil() const {return m_validUntil;}
400 const DOMElement* m_root;
401 const IEntitiesDescriptor* m_parent;
403 vector<const IEntitiesDescriptor*> m_groups;
404 vector<const IEntityDescriptor*> m_providers;
405 vector<const IKeyAuthority*> m_keyauths;
409 XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
410 : ReloadableXMLFileImpl(pathname), m_rootProvider(NULL), m_rootGroup(NULL), m_outer(wrapper) { init(); }
411 XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
412 : ReloadableXMLFileImpl(e), m_rootProvider(NULL), m_rootGroup(NULL), m_outer(wrapper) { init(); }
416 typedef multimap<string,const EntityDescriptor*> sitemap_t;
417 typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
421 EntityDescriptor* m_rootProvider;
422 EntitiesDescriptor* m_rootGroup;
423 const XMLMetadata* m_outer;
426 class XMLMetadata : public IMetadata, public ReloadableXMLFile
429 XMLMetadata(const DOMElement* e);
430 ~XMLMetadata() {delete m_credResolver;}
432 const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
433 const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
434 const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
435 const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
436 const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
437 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
439 bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
442 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
443 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
446 bool m_exclusions,m_verify;
448 ICredResolver* m_credResolver;
452 IPlugIn* XMLMetadataFactory(const DOMElement* e)
454 auto_ptr<XMLMetadata> m(new XMLMetadata(e));
455 m->getImplementation();
459 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
461 return new XMLMetadataImpl(e,this);
464 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
466 return new XMLMetadataImpl(pathname,this);
469 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e)
470 : m_root(e), m_type(IContactPerson::other), m_givenName(NULL), m_surName(NULL), m_company(NULL)
472 const XMLCh* type=NULL;
474 // Old metadata or new?
475 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
476 type=e->getAttributeNS(NULL,SHIB_L(Type));
477 m_surName=toUTF8(e->getAttributeNS(NULL,SHIB_L(Name)));
478 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
479 char* temp = toUTF8(e->getAttributeNS(NULL,SHIB_L(Email)));
481 m_emails.push_back(temp);
485 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
486 type=e->getAttributeNS(NULL,SHIB_L(contactType));
488 e=saml::XML::getFirstChildElement(e);
490 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company))) {
491 n=e->getFirstChild();
492 if (n) m_company=toUTF8(n->getNodeValue());
494 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName))) {
495 n=e->getFirstChild();
496 if (n) m_givenName=toUTF8(n->getNodeValue());
498 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName))) {
499 n=e->getFirstChild();
500 if (n) m_surName=toUTF8(n->getNodeValue());
502 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress))) {
503 n=e->getFirstChild();
505 char* temp = toUTF8(n->getNodeValue());
506 if (temp) m_emails.push_back(temp);
510 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber))) {
511 n=e->getFirstChild();
513 char* temp = toUTF8(n->getNodeValue());
514 if (temp) m_phones.push_back(temp);
518 e=saml::XML::getNextSiblingElement(e);
522 if (!XMLString::compareString(type,SHIB_L(technical)))
523 m_type=IContactPerson::technical;
524 else if (!XMLString::compareString(type,SHIB_L(support)))
525 m_type=IContactPerson::support;
526 else if (!XMLString::compareString(type,SHIB_L(administrative)))
527 m_type=IContactPerson::administrative;
528 else if (!XMLString::compareString(type,SHIB_L(billing)))
529 m_type=IContactPerson::billing;
532 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
535 e=saml::XML::getFirstChildElement(e);
537 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
538 n=e->getFirstChild();
540 char* name = toUTF8(n->getNodeValue());
541 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
542 m_names[lang.get()]=name;
546 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
547 n=e->getFirstChild();
549 char* display = toUTF8(n->getNodeValue());
550 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
551 m_displays[lang.get()]=display;
555 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
556 n=e->getFirstChild();
558 char* url = toUTF8(n->getNodeValue());
559 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
560 m_urls[lang.get()]=url;
564 e=saml::XML::getNextSiblingElement(e);
568 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
570 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
571 e=saml::XML::getFirstChildElement(e);
573 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
574 DOMNode* n=e->getFirstChild();
575 if (n) m_size=XMLString::parseInt(n->getNodeValue());
577 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
578 DOMNode* n=e->getFirstChild();
579 if (n) m_digest=n->getNodeValue();
581 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
582 DOMNode* n=e->getFirstChild();
583 if (n) m_params=n->getNodeValue();
585 e=saml::XML::getNextSiblingElement(e);
589 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
592 saml::NDC ndc("KeyDescriptor");
594 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
596 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
599 m_klist = new DSIGKeyInfoList(NULL);
601 // Process ds:KeyInfo
602 e=saml::XML::getFirstChildElement(e);
604 // We let XMLSec hack through anything it can. This should evolve over time, or we can
605 // plug in our own KeyResolver later...
607 if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
608 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
609 "skipping ds:KeyInfo element containing unsupported children"
612 catch (XSECCryptoException& xe) {
613 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
616 // Check for encryption methods.
617 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod));
619 m_methods.push_back(new EncryptionMethod(e));
620 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod));
624 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
626 for (vector<const XENCEncryptionMethod*>::iterator i=m_methods.begin(); i!=m_methods.end(); i++)
627 delete const_cast<XENCEncryptionMethod*>(*i);
631 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
634 saml::NDC ndc("KeyAuthority");
636 if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
637 m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
639 // Process ds:KeyInfo children
640 e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
642 auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
644 // We let XMLSec hack through anything it can. This should evolve over time, or we can
645 // plug in our own KeyResolver later...
646 DOMElement* child=saml::XML::getFirstChildElement(e);
649 if (!klist->addXMLKeyInfo(child)) {
650 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
651 "skipped unresolvable ds:KeyInfo child element");
654 catch (XSECCryptoException& xe) {
655 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
656 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
658 child=saml::XML::getNextSiblingElement(child);
661 if (klist->getSize()>0)
662 m_klists.push_back(klist.release());
664 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
665 "skipping ds:KeyInfo with no resolvable child elements");
666 e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
670 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
672 for (vector<DSIGKeyInfoList*>::iterator i=m_klists.begin(); i!=m_klists.end(); i++)
676 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
677 : m_provider(provider), m_root(e), m_protocolEnumCopy(NULL), m_errorURL(NULL), m_org(NULL), m_validUntil(validUntil)
679 // Check the root element namespace. If SAML2, assume it's the std schema.
680 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
682 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
683 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
685 m_validUntil=min(m_validUntil,exp.getEpoch());
688 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
689 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
691 // Chop the protocol list into pieces...assume any whitespace can appear in between.
692 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
693 XMLCh* temp=m_protocolEnumCopy;
694 while (temp && *temp) {
696 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
699 m_protocolEnum.push_back(start);
700 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
703 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
705 m_keys.push_back(new KeyDescriptor(e));
706 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
709 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
711 m_org=new Organization(e);
713 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
715 m_contacts.push_back(new ContactPerson(e));
716 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
721 XMLMetadataImpl::Role::~Role()
725 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
726 for (vector<const IKeyDescriptor*>::iterator i=m_keys.begin(); i!=m_keys.end(); i++)
727 delete const_cast<IKeyDescriptor*>(*i);
728 for (vector<const IContactPerson*>::iterator j=m_contacts.begin(); j!=m_contacts.end(); j++)
729 delete const_cast<IContactPerson*>(*j);
732 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
734 Iterator<const XMLCh*> i(m_protocolEnum);
735 while (i.hasNext()) {
736 if (!XMLString::compareString(protocol,i.next()))
742 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
743 : Role(provider,validUntil,e)
745 // Check the root element namespace. If SAML2, assume it's the std schema.
746 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
748 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
749 for (i=0; nlist && i<nlist->getLength(); i++)
750 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
752 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
753 for (i=0; nlist && i<nlist->getLength(); i++)
754 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
756 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
757 for (i=0; nlist && i<nlist->getLength(); i++)
758 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
760 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
761 for (i=0; nlist && i<nlist->getLength(); i++) {
762 DOMNode* n=nlist->item(i)->getFirstChild();
763 if (n) m_formats.push_back(n->getNodeValue());
767 // For old style, we just do SAML 1.1 compatibility with Shib handles.
768 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
769 m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
773 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
775 // Check the root element namespace. If SAML2, assume it's the std schema.
776 DOMNodeList* nlist=NULL;
777 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
778 e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
779 if (e) nlist=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
782 nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
785 for (XMLSize_t i=0; nlist && i < nlist->getLength(); i++) {
786 const XMLCh* dom=(nlist->item(i)->hasChildNodes()) ? nlist->item(i)->getFirstChild()->getNodeValue() : NULL;
788 const XMLCh* regexp=static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
790 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
796 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
797 : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
799 // Check the root element namespace. If SAML2, assume it's the std schema.
800 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
801 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
802 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
804 // Check for SourceID extension.
805 DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
807 ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
808 if (ext && ext->hasChildNodes())
809 m_sourceId=ext->getFirstChild()->getNodeValue();
813 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
814 for (i=0; nlist && i<nlist->getLength(); i++)
815 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
817 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
818 for (i=0; nlist && i<nlist->getLength(); i++)
819 m_mapping.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(AttributeProfile));
826 for (i=0; nlist && i<nlist->getLength(); i++) {
827 DOMNode* n=nlist->item(i)->getFirstChild();
828 if (n) m_attrprofs.push_back(n->getNodeValue());
831 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
832 for (i=0; nlist && i<nlist->getLength(); i++) {
833 // For now, we need to convert these to plain SAML 1.1 attributes.
834 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
835 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
836 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
837 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
838 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
840 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
841 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
842 DOMNamedNodeMap* attrs = src->getAttributes();
843 for (XMLSize_t j=0; j<attrs->getLength(); j++)
844 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
845 while (src->hasChildNodes())
846 val->appendChild(src->getFirstChild());
847 copy->appendChild(val);
849 m_attrs.push_back(SAMLAttribute::getInstance(copy));
853 m_protocolEnum.push_back(Constants::SHIB_NS);
854 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
856 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
857 for (i=0; nlist && i<nlist->getLength(); i++) {
858 // Manufacture an endpoint for the "Shib" binding.
860 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
863 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
864 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
865 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
866 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
868 e->getOwnerDocument()->createTextNode(
869 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
874 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
875 m_keys.push_back(new KeyDescriptor(kd));
880 XMLMetadataImpl::IDPRole::~IDPRole()
882 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
883 delete const_cast<SAMLAttribute*>(*i);
886 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
887 : Role(provider,validUntil,e), ScopedRole(e)
889 // Check the root element namespace. If SAML2, assume it's the std schema.
890 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
892 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
893 for (i=0; nlist && i<nlist->getLength(); i++)
894 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
896 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
897 for (i=0; nlist && i<nlist->getLength(); i++)
898 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
900 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
901 for (i=0; nlist && i<nlist->getLength(); i++) {
902 DOMNode* n=nlist->item(i)->getFirstChild();
903 if (n) m_formats.push_back(n->getNodeValue());
906 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
907 for (i=0; nlist && i<nlist->getLength(); i++) {
908 DOMNode* n=nlist->item(i)->getFirstChild();
909 if (n) m_attrprofs.push_back(n->getNodeValue());
912 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
913 for (i=0; nlist && i<nlist->getLength(); i++) {
914 // For now, we need to convert these to plain SAML 1.1 attributes.
915 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
916 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
917 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
918 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
919 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
921 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
922 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
923 DOMNamedNodeMap* attrs = src->getAttributes();
924 for (XMLSize_t j=0; j<attrs->getLength(); j++)
925 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
926 while (src->hasChildNodes())
927 val->appendChild(src->getFirstChild());
928 copy->appendChild(val);
930 m_attrs.push_back(SAMLAttribute::getInstance(copy));
934 // For old style, we just do SAML 1.1 compatibility with Shib handles.
935 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
936 m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
937 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
939 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
940 for (i=0; nlist && i<nlist->getLength(); i++) {
941 // Manufacture an endpoint for the SOAP binding.
945 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
949 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
950 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
951 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
952 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
954 e->getOwnerDocument()->createTextNode(
955 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
960 m_keys.push_back(new KeyDescriptor(kd));
965 XMLMetadataImpl::AARole::~AARole()
967 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
968 delete const_cast<SAMLAttribute*>(*i);
971 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
972 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
973 ) : m_root(e), m_parent(parent), m_id(NULL), m_errorURL(NULL), m_org(NULL), m_validUntil(validUntil)
975 // Check the root element namespace. If SAML2, assume it's the std schema.
976 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
977 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
979 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
980 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
982 m_validUntil=min(validUntil,exp.getEpoch());
985 DOMElement* child=saml::XML::getFirstChildElement(e);
987 // Process the various kinds of children that we care about...
988 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
989 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
991 m_keyauths.push_back(new KeyAuthority(ext));
992 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
995 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
996 m_contacts.push_back(new ContactPerson(child));
998 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
999 m_org=new Organization(child);
1001 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
1002 DOMNode* loc=child->getFirstChild();
1005 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
1008 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
1009 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
1010 m_roles.push_back(new IDPRole(this,m_validUntil,child));
1012 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
1013 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
1014 m_roles.push_back(new AARole(this,m_validUntil,child));
1016 child = saml::XML::getNextSiblingElement(child);
1020 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
1021 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL)));
1023 bool idp=false,aa=false; // only want to build a role once
1024 DOMElement* child=saml::XML::getFirstChildElement(e);
1026 // Process the various kinds of OriginSite children that we care about...
1027 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
1028 m_contacts.push_back(new ContactPerson(child));
1030 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
1031 // Create the IDP role if needed.
1032 m_roles.push_back(new IDPRole(this, m_validUntil, e));
1035 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
1036 // Create the AA role if needed.
1037 m_roles.push_back(new AARole(this, m_validUntil, e));
1040 child = saml::XML::getNextSiblingElement(child);
1044 if (m_id && *m_id) {
1045 auto_ptr_char id(m_id);
1046 wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1048 // Look for an IdP role, and register the artifact source ID and endpoints.
1049 const IDPRole* idp=NULL;
1050 for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1051 if (idp=dynamic_cast<const IDPRole*>(*r)) {
1052 if (idp->m_sourceId) {
1053 auto_ptr_char sourceid(idp->m_sourceId);
1054 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1057 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1058 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1060 Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1061 while (locs.hasNext()) {
1062 auto_ptr_char loc(locs.next()->getLocation());
1063 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1070 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1072 const IIDPSSODescriptor* ret=NULL;
1073 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1074 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1080 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1082 const IAttributeAuthorityDescriptor* ret=NULL;
1083 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1084 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1090 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1092 delete[] m_errorURL;
1094 for (vector<const IContactPerson*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
1095 delete const_cast<IContactPerson*>(*i);
1096 for (vector<const IRoleDescriptor*>::iterator j=m_roles.begin(); j!=m_roles.end(); j++)
1097 delete const_cast<IRoleDescriptor*>(*j);
1098 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1099 delete const_cast<IKeyAuthority*>(*k);
1102 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1103 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1104 ) : m_root(e), m_parent(parent), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_validUntil(validUntil)
1106 // Check the root element namespace. If SAML2, assume it's the std schema.
1107 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1109 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1110 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1111 exp.parseDateTime();
1112 m_validUntil=min(validUntil,exp.getEpoch());
1115 e=saml::XML::getFirstChildElement(e);
1117 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1118 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1120 m_keyauths.push_back(new KeyAuthority(ext));
1121 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1124 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1125 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1126 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1128 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1129 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1130 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1132 e=saml::XML::getNextSiblingElement(e);
1136 e=saml::XML::getFirstChildElement(e);
1138 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1139 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1140 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1142 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1143 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1144 e=saml::XML::getNextSiblingElement(e);
1148 if (!saml::XML::isEmpty(m_name)) {
1149 auto_ptr_char n(m_name);
1150 wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1156 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1158 for (vector<const IEntityDescriptor*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
1159 delete const_cast<IEntityDescriptor*>(*i);
1160 for (vector<const IEntitiesDescriptor*>::iterator j=m_groups.begin(); j!=m_groups.end(); j++)
1161 delete const_cast<IEntitiesDescriptor*>(*j);
1162 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1163 delete const_cast<IKeyAuthority*>(*k);
1166 void XMLMetadataImpl::init()
1171 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1175 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1176 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1177 m_rootGroup=new EntitiesDescriptor(m_root,this);
1179 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1180 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1181 m_rootProvider=new EntityDescriptor(m_root,this);
1183 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1184 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1185 m_rootGroup=new EntitiesDescriptor(m_root,this);
1187 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1188 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1189 m_rootProvider=new EntityDescriptor(m_root,this);
1192 log.error("Construction requires a valid SAML metadata file");
1193 throw MetadataException("Construction requires a valid SAML metadata file");
1196 catch (SAMLException& e)
1198 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << xmlproviders::logging::eol;
1199 this->~XMLMetadataImpl();
1205 log.error("Unexpected error while parsing SAML metadata");
1206 this->~XMLMetadataImpl();
1211 if (!m_rootGroup && !m_rootProvider) {
1212 log.error("Metadata file contained no valid information");
1213 throw MetadataException("Metadata file contained no valid information");
1217 XMLMetadataImpl::~XMLMetadataImpl()
1220 delete m_rootProvider;
1223 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1225 static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1226 if (e->hasAttributeNS(NULL,uri)) {
1227 // First check for explicit enablement of entities.
1228 DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1229 for (XMLSize_t i=0; nlist && i<nlist->getLength(); i++) {
1230 if (nlist->item(i)->hasChildNodes()) {
1231 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1233 m_set.insert(temp.get());
1238 // If there was no explicit enablement, build a set of exclusions.
1240 nlist=e->getElementsByTagName(SHIB_L(Exclude));
1241 for (XMLSize_t j=0; nlist && j<nlist->getLength(); j++) {
1242 if (nlist->item(j)->hasChildNodes()) {
1243 auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1245 m_set.insert(temp.get());
1251 const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1252 m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1255 DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1257 cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";
1259 r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1261 auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1266 if (!cr_type.empty()) {
1268 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1269 ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1273 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1275 throw UnsupportedExtensionException("plugin was not a credential resolver");
1278 catch (SAMLException& e) {
1279 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1284 if (m_verify && !m_credResolver) {
1285 delete m_credResolver;
1286 throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1290 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1296 saml::NDC ndc("verifySignature");
1298 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1300 DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1303 log.error("rejecting unsigned element");
1309 XSECCryptoX509* cert=NULL;
1310 Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1311 if (certs.hasNext())
1314 log.error("unable to find any certificates to use in verifying signature");
1318 static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1319 static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1321 // Load the signature.
1323 DSIGSignature* sig=NULL;
1325 sig=prov.newSignatureFromDOM(doc,sigNode);
1329 const XMLCh* URI=NULL;
1331 // Verify the signature coverage.
1332 DSIGReferenceList* refs=sig->getReferenceList();
1333 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1334 DSIGReference* ref=refs->item(0);
1337 if (!URI || !*URI || (*URI==chPound &&
1338 !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1339 DSIGTransformList* tlist=ref->getTransforms();
1340 for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
1341 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1343 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1344 tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1354 auto_ptr_char temp((URI && *URI) ? URI : null);
1355 log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1359 sig->setSigningKey(cert->clonePublicKey());
1360 if (!sig->verify()) {
1361 auto_ptr_char temp((URI && *URI) ? URI : null);
1362 log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1366 prov.releaseSignature(sig);
1368 catch(XSECException& e) {
1369 auto_ptr_char msg(e.getMsg());
1370 log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << xmlproviders::logging::eol;
1372 prov.releaseSignature(sig);
1375 catch(XSECCryptoException& e) {
1376 log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << xmlproviders::logging::eol;
1378 prov.releaseSignature(sig);
1383 prov.releaseSignature(sig);
1384 log.error("caught unknown exception while verifying metadata signature");
1390 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1392 if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1394 else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1397 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1398 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1399 impl->m_sites.equal_range(providerId);
1401 time_t now=time(NULL);
1402 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1403 if (now < i->second->getValidUntil())
1406 if (!strict && range.first!=range.second)
1407 return range.first->second;
1412 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1414 auto_ptr_char temp(providerId);
1415 return lookup(temp.get(),strict);
1418 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1420 time_t now=time(NULL);
1421 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1422 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1424 // Depends on type of artifact.
1425 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1427 range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1430 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1432 range=impl->m_sources.equal_range(type2->getSourceLocation());
1438 // Check exclude list.
1439 if (range.first!=range.second) {
1440 auto_ptr_char id(range.first->second->getId());
1441 if (m_exclusions && m_set.find(id.get())!=m_set.end())
1443 else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1446 for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1447 if (now < i->second->getValidUntil())
1454 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1456 if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1458 else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1461 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1462 pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1463 impl->m_groups.equal_range(name);
1465 time_t now=time(NULL);
1466 for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1467 if (now < i->second->getValidUntil())
1470 if (!strict && range.first!=range.second)
1471 return range.first->second;
1476 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1478 auto_ptr_char temp(name);
1479 return lookupGroup(temp.get(),strict);
1482 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1484 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1485 return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);