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 <log4cpp/Category.hh>
32 #include <xercesc/util/XMLChar.hpp>
33 #include <xsec/dsig/DSIGTransformC14n.hpp>
34 #include <xsec/dsig/DSIGReference.hpp>
35 #include <xsec/dsig/DSIGTransformList.hpp>
36 #include <xsec/enc/XSECCryptoException.hpp>
37 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
38 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
39 #include <xsec/framework/XSECException.hpp>
40 #include <xsec/framework/XSECProvider.hpp>
42 using namespace shibboleth;
44 using namespace log4cpp;
50 class XMLMetadataImpl : public ReloadableXMLFileImpl
53 class ContactPerson : public IContactPerson
56 ContactPerson(const DOMElement* e);
59 ContactType getType() const { return m_type; }
60 const char* getCompany() const { return m_company.get(); }
61 const char* getGivenName() const { return m_givenName.get(); }
62 const char* getSurName() const { return m_surName.get(); }
63 Iterator<string> getEmailAddresses() const { return m_emails; }
64 Iterator<string> getTelephoneNumbers() const { return m_phones; }
65 const DOMElement* getElement() const { return m_root; }
68 const DOMElement* m_root;
70 auto_ptr<char> m_givenName,m_surName,m_company;
71 vector<string> m_emails,m_phones;
74 class Organization : public IOrganization
77 Organization(const DOMElement* e);
80 const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
81 const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
82 const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
83 const DOMElement* getElement() const { return m_root; }
86 const char* forLang(const map<string,string>& m, const char* lang) const {
87 map<string,string>::const_iterator i=m.find(lang);
88 return (i==m.end()) ? NULL : i->second.c_str();
90 const DOMElement* m_root;
91 map<string,string> m_names,m_displays,m_urls;
94 class EntityDescriptor;
96 class EncryptionMethod : public XENCEncryptionMethod
99 EncryptionMethod(const DOMElement* e);
100 ~EncryptionMethod() {}
102 const XMLCh * getAlgorithm(void) const { return m_alg; }
103 const XMLCh * getDigestMethod(void) const { return m_digest; }
104 const XMLCh * getOAEPparams(void) const { return m_params; }
105 int getKeySize(void) const { return m_size; }
106 DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
107 void setDigestMethod(const XMLCh * method) {throw exception();}
108 void setOAEPparams(const XMLCh * params) {throw exception();}
109 void setKeySize(int size) {throw exception();}
112 const DOMElement* m_root;
114 const XMLCh* m_digest;
115 const XMLCh* m_params;
119 class KeyDescriptor : public IKeyDescriptor
122 KeyDescriptor(const DOMElement* e);
125 KeyUse getUse() const { return m_use; }
126 DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
127 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
128 const DOMElement* getElement() const { return m_root; }
131 const DOMElement* m_root;
133 mutable DSIGKeyInfoList* m_klist;
134 vector<const XENCEncryptionMethod*> m_methods;
137 class KeyAuthority : public IKeyAuthority
140 KeyAuthority(const DOMElement* e);
143 int getVerifyDepth() const { return m_depth; }
144 Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
148 vector<DSIGKeyInfoList*> m_klists;
151 class Role : public virtual IRoleDescriptor
154 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
158 const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
159 Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
160 bool hasSupport(const XMLCh* protocol) const;
161 const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
162 bool isValid() const {return time(NULL) < m_validUntil;}
163 Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
164 const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
165 Iterator<const IContactPerson*> getContactPersons() const
166 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
167 const DOMElement* getElement() const {return m_root;}
170 vector<const XMLCh*> m_protocolEnum;
171 vector<const IKeyDescriptor*> m_keys;
174 const EntityDescriptor* m_provider;
175 const DOMElement* m_root;
176 XMLCh* m_protocolEnumCopy;
179 vector<const IContactPerson*> m_contacts;
183 class Endpoint : public virtual IEndpoint
186 Endpoint(const DOMElement* e) : m_root(e),
187 m_binding(e->getAttributeNS(NULL,L(Binding))),
188 m_location(e->getAttributeNS(NULL,L(Location))),
189 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
190 Endpoint(const XMLCh* binding, const XMLCh* loc)
191 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
194 const XMLCh* getBinding() const { return m_binding; }
195 const XMLCh* getLocation() const { return m_location; }
196 const XMLCh* getResponseLocation() const { return m_resploc; }
197 const DOMElement* getElement() const { return m_root; }
200 const DOMElement* m_root;
201 const XMLCh* m_binding;
202 const XMLCh* m_location;
203 const XMLCh* m_resploc;
206 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
209 IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
210 unsigned short getIndex() const {return m_index;}
213 unsigned short m_index;
216 class EndpointManager : public IEndpointManager
219 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
221 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
222 delete const_cast<IEndpoint*>(*i);
224 saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
225 const IEndpoint* getDefaultEndpoint() const {
226 if (m_hard) return m_hard;
227 if (m_soft) return m_soft;
228 if (!m_endpoints.empty()) return *(m_endpoints.begin());
231 const IEndpoint* getEndpointByIndex(unsigned short index) const {
232 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
233 const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
234 if (temp && index==temp->getIndex())
239 const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
240 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
241 if (!XMLString::compareString(binding,(*i)->getBinding()))
245 void add(IEndpoint* e) {
246 m_endpoints.push_back(e);
247 if (!m_hard && e->getElement()) {
248 const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
249 if (v && (*v==chDigit_1 || *v==chLatin_t)) // explicit default
251 else if ((!v || !*v) && !m_soft) // implicit default
254 else if (!m_hard && !m_soft) {
255 // No default yet, so this one qualifies as an implicit.
261 vector<const IEndpoint*> m_endpoints;
262 const IEndpoint* m_soft; // Soft default (not explicit)
263 const IEndpoint* m_hard; // Hard default (explicit)
266 class SSORole : public Role, public virtual ISSODescriptor
269 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
271 const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
272 const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
273 const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
274 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
277 EndpointManager m_artifact,m_logout,m_nameid;
278 vector<const XMLCh*> m_formats;
281 class ScopedRole : public virtual IScopedRoleDescriptor
284 ScopedRole(const DOMElement* e);
285 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
288 vector<pair<const XMLCh*,bool> > m_scopes;
291 class IDPRole : public SSORole, public ScopedRole, public virtual IIDPSSODescriptor
294 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
296 bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
297 const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
298 const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
299 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
300 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
301 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
304 EndpointManager m_sso,m_mapping,m_idreq;
305 vector<const XMLCh*> m_attrprofs;
306 vector<const SAMLAttribute*> m_attrs;
307 bool m_wantAuthnRequestsSigned;
308 const XMLCh* m_sourceId;
309 friend class EntityDescriptor;
312 class AARole : public Role, public ScopedRole, public virtual IAttributeAuthorityDescriptor
315 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
317 const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
318 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
319 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
320 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
321 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
324 EndpointManager m_query,m_idreq;
325 vector<const XMLCh*> m_formats,m_attrprofs;
326 vector<const SAMLAttribute*> m_attrs;
329 class EntityDescriptor : public IExtendedEntityDescriptor
334 XMLMetadataImpl* wrapper,
335 time_t validUntil=LONG_MAX,
336 const IEntitiesDescriptor* parent=NULL
341 const XMLCh* getId() const {return m_id;}
342 bool isValid() const {return time(NULL) < m_validUntil;}
343 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
344 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
345 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
346 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
347 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
348 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
349 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
350 const IOrganization* getOrganization() const {return m_org;}
351 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
352 Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
353 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
354 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
355 const DOMElement* getElement() const {return m_root;}
358 const char* getErrorURL() const {return m_errorURL.get();}
359 time_t getValidUntil() const {return m_validUntil;}
361 const DOMElement* m_root;
362 const IEntitiesDescriptor* m_parent;
364 auto_ptr<char> m_errorURL;
365 IOrganization* m_org;
366 vector<const IContactPerson*> m_contacts;
367 vector<const IRoleDescriptor*> m_roles;
368 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
369 vector<const IKeyAuthority*> m_keyauths;
373 class EntitiesDescriptor : public IExtendedEntitiesDescriptor
378 XMLMetadataImpl* wrapper,
379 time_t validUntil=LONG_MAX,
380 const IEntitiesDescriptor* parent=NULL
382 ~EntitiesDescriptor();
384 const XMLCh* getName() const {return m_name;}
385 bool isValid() const {return time(NULL) < m_validUntil;}
386 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
387 Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
388 Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
389 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
390 const DOMElement* getElement() const {return m_root;}
393 time_t getValidUntil() const {return m_validUntil;}
395 const DOMElement* m_root;
396 const IEntitiesDescriptor* m_parent;
398 vector<const IEntitiesDescriptor*> m_groups;
399 vector<const IEntityDescriptor*> m_providers;
400 vector<const IKeyAuthority*> m_keyauths;
404 XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
405 : ReloadableXMLFileImpl(pathname), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
406 XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
407 : ReloadableXMLFileImpl(e), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
411 typedef multimap<string,const EntityDescriptor*> sitemap_t;
412 typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
416 EntityDescriptor* m_rootProvider;
417 EntitiesDescriptor* m_rootGroup;
418 const XMLMetadata* m_outer;
421 class XMLMetadata : public IMetadata, public ReloadableXMLFile
424 XMLMetadata(const DOMElement* e);
425 ~XMLMetadata() {delete m_credResolver;}
427 const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
428 const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
429 const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
430 const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
431 const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
432 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
434 bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
437 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
438 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
441 bool m_exclusions,m_verify;
443 ICredResolver* m_credResolver;
447 IPlugIn* XMLMetadataFactory(const DOMElement* e)
449 auto_ptr<XMLMetadata> m(new XMLMetadata(e));
450 m->getImplementation();
454 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
456 return new XMLMetadataImpl(e,this);
459 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
461 return new XMLMetadataImpl(pathname,this);
464 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
466 const XMLCh* type=NULL;
468 // Old metadata or new?
469 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
470 type=e->getAttributeNS(NULL,SHIB_L(Type));
471 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
473 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
474 auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
476 m_emails.push_back(temp.get());
479 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
480 type=e->getAttributeNS(NULL,SHIB_L(contactType));
481 e=saml::XML::getFirstChildElement(e);
483 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company)) && e->hasChildNodes()) {
484 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
487 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName)) && e->hasChildNodes()) {
488 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
491 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName)) && e->hasChildNodes()) {
492 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
495 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress)) && e->hasChildNodes()) {
496 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
497 if (temp.get()) m_emails.push_back(temp.get());
499 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber)) && e->hasChildNodes()) {
500 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
501 if (temp.get()) m_phones.push_back(temp.get());
503 e=saml::XML::getNextSiblingElement(e);
507 if (!XMLString::compareString(type,SHIB_L(technical)))
508 m_type=IContactPerson::technical;
509 else if (!XMLString::compareString(type,SHIB_L(support)))
510 m_type=IContactPerson::support;
511 else if (!XMLString::compareString(type,SHIB_L(administrative)))
512 m_type=IContactPerson::administrative;
513 else if (!XMLString::compareString(type,SHIB_L(billing)))
514 m_type=IContactPerson::billing;
515 else if (!XMLString::compareString(type,SHIB_L(other)))
516 m_type=IContactPerson::other;
519 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
522 e=saml::XML::getFirstChildElement(e);
524 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
525 n=e->getFirstChild();
527 auto_ptr<char> name(toUTF8(n->getNodeValue()));
528 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
529 m_names[lang.get()]=name.get();
532 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
533 n=e->getFirstChild();
535 auto_ptr<char> display(toUTF8(n->getNodeValue()));
536 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
537 m_displays[lang.get()]=display.get();
540 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
541 n=e->getFirstChild();
543 auto_ptr<char> url(toUTF8(n->getNodeValue()));
544 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
545 m_urls[lang.get()]=url.get();
548 e=saml::XML::getNextSiblingElement(e);
552 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
554 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
555 e=saml::XML::getFirstChildElement(e);
557 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
558 DOMNode* n=e->getFirstChild();
559 if (n) m_size=XMLString::parseInt(n->getNodeValue());
561 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
562 DOMNode* n=e->getFirstChild();
563 if (n) m_digest=n->getNodeValue();
565 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
566 DOMNode* n=e->getFirstChild();
567 if (n) m_params=n->getNodeValue();
569 e=saml::XML::getNextSiblingElement(e);
573 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
576 saml::NDC ndc("KeyDescriptor");
578 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
580 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
583 m_klist = new DSIGKeyInfoList(NULL);
585 // Process ds:KeyInfo
586 e=saml::XML::getFirstChildElement(e);
588 // We let XMLSec hack through anything it can. This should evolve over time, or we can
589 // plug in our own KeyResolver later...
591 if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
592 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
593 "skipping ds:KeyInfo element containing unsupported children"
596 catch (XSECCryptoException& xe) {
597 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
600 // Check for encryption methods.
601 e=saml::XML::getNextSiblingElement(e);
602 while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
603 m_methods.push_back(new EncryptionMethod(e));
606 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
608 for (vector<const XENCEncryptionMethod*>::iterator i=m_methods.begin(); i!=m_methods.end(); i++)
609 delete const_cast<XENCEncryptionMethod*>(*i);
613 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
616 saml::NDC ndc("KeyAuthority");
618 if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
619 m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
621 // Process ds:KeyInfo children
622 e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
624 auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
626 // We let XMLSec hack through anything it can. This should evolve over time, or we can
627 // plug in our own KeyResolver later...
628 DOMElement* child=saml::XML::getFirstChildElement(e);
631 if (!klist->addXMLKeyInfo(child)) {
632 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
633 "skipped unresolvable ds:KeyInfo child element");
636 catch (XSECCryptoException& xe) {
637 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
638 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
640 child=saml::XML::getNextSiblingElement(child);
643 if (klist->getSize()>0)
644 m_klists.push_back(klist.release());
646 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
647 "skipping ds:KeyInfo with no resolvable child elements");
648 e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
652 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
654 for (vector<DSIGKeyInfoList*>::iterator i=m_klists.begin(); i!=m_klists.end(); i++)
658 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
659 : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
661 // Check the root element namespace. If SAML2, assume it's the std schema.
662 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
664 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
665 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
667 m_validUntil=min(m_validUntil,exp.getEpoch());
670 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
671 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
673 // Chop the protocol list into pieces...assume any whitespace can appear in between.
674 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
675 XMLCh* temp=m_protocolEnumCopy;
676 while (temp && *temp) {
678 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
681 m_protocolEnum.push_back(start);
682 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
685 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
687 m_keys.push_back(new KeyDescriptor(e));
688 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
691 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
693 m_org=new Organization(e);
695 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
697 m_contacts.push_back(new ContactPerson(e));
698 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
703 XMLMetadataImpl::Role::~Role()
707 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
708 for (vector<const IKeyDescriptor*>::iterator i=m_keys.begin(); i!=m_keys.end(); i++)
709 delete const_cast<IKeyDescriptor*>(*i);
710 for (vector<const IContactPerson*>::iterator j=m_contacts.begin(); j!=m_contacts.end(); j++)
711 delete const_cast<IContactPerson*>(*j);
714 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
716 Iterator<const XMLCh*> i(m_protocolEnum);
717 while (i.hasNext()) {
718 if (!XMLString::compareString(protocol,i.next()))
724 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
725 : Role(provider,validUntil,e)
727 // Check the root element namespace. If SAML2, assume it's the std schema.
728 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
730 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
731 for (i=0; nlist && i<nlist->getLength(); i++)
732 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
734 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
735 for (i=0; nlist && i<nlist->getLength(); i++)
736 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
738 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
739 for (i=0; nlist && i<nlist->getLength(); i++)
740 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
742 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
743 for (i=0; nlist && i<nlist->getLength(); i++) {
744 DOMNode* n=nlist->item(i)->getFirstChild();
745 if (n) m_formats.push_back(n->getNodeValue());
749 // For old style, we just do SAML 1.1 compatibility with Shib handles.
750 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
751 m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
755 XMLMetadataImpl::ScopedRole::ScopedRole(const DOMElement* e)
757 // Check the root element namespace. If SAML2, assume it's the std schema.
758 DOMNodeList* nlist=NULL;
759 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
760 e=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
761 if (e) nlist=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
764 nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
767 for (unsigned int i=0; nlist && i < nlist->getLength(); i++) {
768 const XMLCh* dom=(nlist->item(i)->hasChildNodes()) ? nlist->item(i)->getFirstChild()->getNodeValue() : NULL;
770 const XMLCh* regexp=static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
772 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
778 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
779 : SSORole(provider,validUntil,e), ScopedRole(e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
781 // Check the root element namespace. If SAML2, assume it's the std schema.
782 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
783 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
784 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
786 // Check for SourceID extension.
787 DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
789 ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
790 if (ext && ext->hasChildNodes())
791 m_sourceId=ext->getFirstChild()->getNodeValue();
795 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
796 for (i=0; nlist && i<nlist->getLength(); i++)
797 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
799 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
800 for (i=0; nlist && i<nlist->getLength(); i++)
801 m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
803 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
804 for (i=0; nlist && i<nlist->getLength(); i++)
805 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
807 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
808 for (i=0; nlist && i<nlist->getLength(); i++) {
809 DOMNode* n=nlist->item(i)->getFirstChild();
810 if (n) m_attrprofs.push_back(n->getNodeValue());
813 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
814 for (i=0; nlist && i<nlist->getLength(); i++) {
815 // For now, we need to convert these to plain SAML 1.1 attributes.
816 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
817 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
818 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
819 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
820 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
822 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
823 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
824 DOMNamedNodeMap* attrs = src->getAttributes();
825 for (unsigned int j=0; j<attrs->getLength(); j++)
826 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
827 while (src->hasChildNodes())
828 val->appendChild(src->getFirstChild());
829 copy->appendChild(val);
831 m_attrs.push_back(SAMLAttribute::getInstance(copy));
835 m_protocolEnum.push_back(Constants::SHIB_NS);
836 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
838 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
839 for (i=0; nlist && i<nlist->getLength(); i++) {
840 // Manufacture an endpoint for the "Shib" binding.
842 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
845 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
846 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
847 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
848 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
850 e->getOwnerDocument()->createTextNode(
851 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
856 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
857 m_keys.push_back(new KeyDescriptor(kd));
862 XMLMetadataImpl::IDPRole::~IDPRole()
864 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
865 delete const_cast<SAMLAttribute*>(*i);
868 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
869 : Role(provider,validUntil,e), ScopedRole(e)
871 // Check the root element namespace. If SAML2, assume it's the std schema.
872 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
874 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
875 for (i=0; nlist && i<nlist->getLength(); i++)
876 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
878 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
879 for (i=0; nlist && i<nlist->getLength(); i++)
880 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
882 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
883 for (i=0; nlist && i<nlist->getLength(); i++) {
884 DOMNode* n=nlist->item(i)->getFirstChild();
885 if (n) m_formats.push_back(n->getNodeValue());
888 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
889 for (i=0; nlist && i<nlist->getLength(); i++) {
890 DOMNode* n=nlist->item(i)->getFirstChild();
891 if (n) m_attrprofs.push_back(n->getNodeValue());
894 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
895 for (i=0; nlist && i<nlist->getLength(); i++) {
896 // For now, we need to convert these to plain SAML 1.1 attributes.
897 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
898 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
899 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
900 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
901 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
903 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
904 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
905 DOMNamedNodeMap* attrs = src->getAttributes();
906 for (unsigned int j=0; j<attrs->getLength(); j++)
907 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
908 while (src->hasChildNodes())
909 val->appendChild(src->getFirstChild());
910 copy->appendChild(val);
912 m_attrs.push_back(SAMLAttribute::getInstance(copy));
916 // For old style, we just do SAML 1.1 compatibility with Shib handles.
917 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
918 m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
919 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
921 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
922 for (i=0; nlist && i<nlist->getLength(); i++) {
923 // Manufacture an endpoint for the SOAP binding.
927 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
931 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
932 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
933 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
934 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
936 e->getOwnerDocument()->createTextNode(
937 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
942 m_keys.push_back(new KeyDescriptor(kd));
947 XMLMetadataImpl::AARole::~AARole()
949 for (vector<const SAMLAttribute*>::iterator i=m_attrs.begin(); i!=m_attrs.end(); i++)
950 delete const_cast<SAMLAttribute*>(*i);
953 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
954 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
955 ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
957 // Check the root element namespace. If SAML2, assume it's the std schema.
958 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
959 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
961 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
962 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
964 m_validUntil=min(validUntil,exp.getEpoch());
967 DOMElement* child=saml::XML::getFirstChildElement(e);
969 // Process the various kinds of children that we care about...
970 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
971 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
973 m_keyauths.push_back(new KeyAuthority(ext));
974 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
977 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
978 m_contacts.push_back(new ContactPerson(child));
980 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
981 m_org=new Organization(child);
983 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
984 DOMNode* loc=child->getFirstChild();
987 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
990 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
991 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
992 m_roles.push_back(new IDPRole(this,m_validUntil,child));
994 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
995 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
996 m_roles.push_back(new AARole(this,m_validUntil,child));
998 child = saml::XML::getNextSiblingElement(child);
1002 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
1003 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
1006 bool idp=false,aa=false; // only want to build a role once
1007 DOMElement* child=saml::XML::getFirstChildElement(e);
1009 // Process the various kinds of OriginSite children that we care about...
1010 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
1011 m_contacts.push_back(new ContactPerson(child));
1013 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
1014 // Create the IDP role if needed.
1015 m_roles.push_back(new IDPRole(this, m_validUntil, e));
1018 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
1019 // Create the AA role if needed.
1020 m_roles.push_back(new AARole(this, m_validUntil, e));
1023 child = saml::XML::getNextSiblingElement(child);
1027 auto_ptr_char id(m_id);
1028 wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1030 // Look for an IdP role, and register the artifact source ID and endpoints.
1031 const IDPRole* idp=NULL;
1032 for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1033 if (idp=dynamic_cast<const IDPRole*>(*r)) {
1034 if (idp->m_sourceId) {
1035 auto_ptr_char sourceid(idp->m_sourceId);
1036 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1039 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1040 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1042 Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1043 while (locs.hasNext()) {
1044 auto_ptr_char loc(locs.next()->getLocation());
1045 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1051 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1053 const IIDPSSODescriptor* ret=NULL;
1054 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1055 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1061 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1063 const IAttributeAuthorityDescriptor* ret=NULL;
1064 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1065 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1071 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1074 for (vector<const IContactPerson*>::iterator i=m_contacts.begin(); i!=m_contacts.end(); i++)
1075 delete const_cast<IContactPerson*>(*i);
1076 for (vector<const IRoleDescriptor*>::iterator j=m_roles.begin(); j!=m_roles.end(); j++)
1077 delete const_cast<IRoleDescriptor*>(*j);
1078 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1079 delete const_cast<IKeyAuthority*>(*k);
1082 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1083 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1084 ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1086 // Check the root element namespace. If SAML2, assume it's the std schema.
1087 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1089 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1090 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1091 exp.parseDateTime();
1092 m_validUntil=min(validUntil,exp.getEpoch());
1095 e=saml::XML::getFirstChildElement(e);
1097 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1098 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1100 m_keyauths.push_back(new KeyAuthority(ext));
1101 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1104 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1105 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1106 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1108 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1109 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1110 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1112 e=saml::XML::getNextSiblingElement(e);
1116 e=saml::XML::getFirstChildElement(e);
1118 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1119 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1120 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1122 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1123 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1124 e=saml::XML::getNextSiblingElement(e);
1128 if (!saml::XML::isEmpty(m_name)) {
1129 auto_ptr_char n(m_name);
1130 wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1136 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1138 for (vector<const IEntityDescriptor*>::iterator i=m_providers.begin(); i!=m_providers.end(); i++)
1139 delete const_cast<IEntityDescriptor*>(*i);
1140 for (vector<const IEntitiesDescriptor*>::iterator j=m_groups.begin(); j!=m_groups.end(); j++)
1141 delete const_cast<IEntitiesDescriptor*>(*j);
1142 for (vector<const IKeyAuthority*>::iterator k=m_keyauths.begin(); k!=m_keyauths.end(); k++)
1143 delete const_cast<IKeyAuthority*>(*k);
1146 void XMLMetadataImpl::init()
1151 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1155 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1156 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1157 m_rootGroup=new EntitiesDescriptor(m_root,this);
1159 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1160 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1161 m_rootProvider=new EntityDescriptor(m_root,this);
1163 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1164 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1165 m_rootGroup=new EntitiesDescriptor(m_root,this);
1167 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1168 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1169 m_rootProvider=new EntityDescriptor(m_root,this);
1172 log.error("Construction requires a valid SAML metadata file");
1173 throw MetadataException("Construction requires a valid SAML metadata file");
1176 catch (SAMLException& e)
1178 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1179 this->~XMLMetadataImpl();
1185 log.error("Unexpected error while parsing SAML metadata");
1186 this->~XMLMetadataImpl();
1191 if (!m_rootGroup && !m_rootProvider) {
1192 log.error("Metadata file contained no valid information");
1193 throw MetadataException("Metadata file contained no valid information");
1197 XMLMetadataImpl::~XMLMetadataImpl()
1200 delete m_rootProvider;
1203 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1205 static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1206 if (e->hasAttributeNS(NULL,uri)) {
1207 // First check for explicit enablement of entities.
1208 DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1209 for (unsigned int i=0; nlist && i<nlist->getLength(); i++) {
1210 if (nlist->item(i)->hasChildNodes()) {
1211 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1213 m_set.insert(temp.get());
1218 // If there was no explicit enablement, build a set of exclusions.
1220 nlist=e->getElementsByTagName(SHIB_L(Exclude));
1221 for (unsigned int j=0; nlist && j<nlist->getLength(); j++) {
1222 if (nlist->item(j)->hasChildNodes()) {
1223 auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1225 m_set.insert(temp.get());
1231 const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1232 m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1235 DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1237 cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";
1239 r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1241 auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1246 if (!cr_type.empty()) {
1248 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1249 ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1253 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1255 throw UnsupportedExtensionException("plugin was not a credential resolver");
1258 catch (SAMLException& e) {
1259 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1264 if (m_verify && !m_credResolver) {
1265 delete m_credResolver;
1266 throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1270 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1276 saml::NDC ndc("verifySignature");
1278 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1280 DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1283 log.error("rejecting unsigned element");
1289 XSECCryptoX509* cert=NULL;
1290 Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1291 if (certs.hasNext())
1294 log.error("unable to find any certificates to use in verifying signature");
1298 static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1299 static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1301 // Load the signature.
1303 DSIGSignature* sig=NULL;
1305 sig=prov.newSignatureFromDOM(doc,sigNode);
1309 const XMLCh* URI=NULL;
1311 // Verify the signature coverage.
1312 DSIGReferenceList* refs=sig->getReferenceList();
1313 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1314 DSIGReference* ref=refs->item(0);
1317 if (!URI || !*URI || (*URI==chPound &&
1318 !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1319 DSIGTransformList* tlist=ref->getTransforms();
1320 for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
1321 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1323 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1324 tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1334 auto_ptr_char temp((URI && *URI) ? URI : null);
1335 log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1339 sig->setSigningKey(cert->clonePublicKey());
1340 if (!sig->verify()) {
1341 auto_ptr_char temp((URI && *URI) ? URI : null);
1342 log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1346 prov.releaseSignature(sig);
1348 catch(XSECException& e) {
1349 auto_ptr_char msg(e.getMsg());
1350 log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << CategoryStream::ENDLINE;
1352 prov.releaseSignature(sig);
1355 catch(XSECCryptoException& e) {
1356 log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << CategoryStream::ENDLINE;
1358 prov.releaseSignature(sig);
1363 prov.releaseSignature(sig);
1364 log.error("caught unknown exception while verifying metadata signature");
1370 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1372 if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1374 else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1377 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1378 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1379 impl->m_sites.equal_range(providerId);
1381 time_t now=time(NULL);
1382 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1383 if (now < i->second->getValidUntil())
1386 if (!strict && range.first!=range.second)
1387 return range.first->second;
1392 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1394 auto_ptr_char temp(providerId);
1395 return lookup(temp.get(),strict);
1398 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1400 time_t now=time(NULL);
1401 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1402 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1404 // Depends on type of artifact.
1405 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1407 range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1410 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1412 range=impl->m_sources.equal_range(type2->getSourceLocation());
1418 // Check exclude list.
1419 if (range.first!=range.second) {
1420 auto_ptr_char id(range.first->second->getId());
1421 if (m_exclusions && m_set.find(id.get())!=m_set.end())
1423 else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1426 for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1427 if (now < i->second->getValidUntil())
1434 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1436 if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1438 else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1441 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1442 pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1443 impl->m_groups.equal_range(name);
1445 time_t now=time(NULL);
1446 for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1447 if (now < i->second->getValidUntil())
1450 if (!strict && range.first!=range.second)
1451 return range.first->second;
1456 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1458 auto_ptr_char temp(name);
1459 return lookupGroup(temp.get(),strict);
1462 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1464 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1465 return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);