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
29 #include <sys/types.h>
32 #include <log4cpp/Category.hh>
33 #include <xercesc/util/XMLChar.hpp>
34 #include <xsec/dsig/DSIGTransformC14n.hpp>
35 #include <xsec/dsig/DSIGReference.hpp>
36 #include <xsec/dsig/DSIGTransformList.hpp>
37 #include <xsec/enc/XSECCryptoException.hpp>
38 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>
39 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
40 #include <xsec/framework/XSECException.hpp>
41 #include <xsec/framework/XSECProvider.hpp>
43 #include <shibsp/SPConstants.h>
45 using namespace shibboleth;
47 using namespace log4cpp;
53 class XMLMetadataImpl : public ReloadableXMLFileImpl
56 class ContactPerson : public IContactPerson
59 ContactPerson(const DOMElement* e);
62 ContactType getType() const { return m_type; }
63 const char* getCompany() const { return m_company.get(); }
64 const char* getGivenName() const { return m_givenName.get(); }
65 const char* getSurName() const { return m_surName.get(); }
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;
73 auto_ptr<char> m_givenName,m_surName,m_company;
74 vector<string> m_emails,m_phones;
77 class Organization : public IOrganization
80 Organization(const DOMElement* e);
83 const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
84 const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
85 const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
86 const DOMElement* getElement() const { return m_root; }
89 const char* forLang(const map<string,string>& m, const char* lang) const {
90 map<string,string>::const_iterator i=m.find(lang);
91 return (i==m.end()) ? NULL : i->second.c_str();
93 const DOMElement* m_root;
94 map<string,string> m_names,m_displays,m_urls;
97 class EntityDescriptor;
99 class EncryptionMethod : public XENCEncryptionMethod
102 EncryptionMethod(const DOMElement* e);
103 ~EncryptionMethod() {}
105 const XMLCh * getAlgorithm(void) const { return m_alg; }
106 const XMLCh * getDigestMethod(void) const { return m_digest; }
107 const XMLCh * getOAEPparams(void) const { return m_params; }
108 int getKeySize(void) const { return m_size; }
109 DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
110 void setDigestMethod(const XMLCh * method) {throw exception();}
111 void setOAEPparams(const XMLCh * params) {throw exception();}
112 void setKeySize(int size) {throw exception();}
115 const DOMElement* m_root;
117 const XMLCh* m_digest;
118 const XMLCh* m_params;
122 class KeyDescriptor : public IKeyDescriptor
125 KeyDescriptor(const DOMElement* e);
128 KeyUse getUse() const { return m_use; }
129 DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
130 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
131 const DOMElement* getElement() const { return m_root; }
134 const DOMElement* m_root;
136 mutable DSIGKeyInfoList* m_klist;
137 vector<const XENCEncryptionMethod*> m_methods;
140 class KeyAuthority : public IKeyAuthority
143 KeyAuthority(const DOMElement* e);
146 int getVerifyDepth() const { return m_depth; }
147 Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
151 vector<DSIGKeyInfoList*> m_klists;
154 class Role : public virtual IRoleDescriptor
157 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
161 const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
162 Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
163 bool hasSupport(const XMLCh* protocol) const;
164 const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
165 bool isValid() const {return time(NULL) < m_validUntil;}
166 Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
167 const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
168 Iterator<const IContactPerson*> getContactPersons() const
169 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
170 const DOMElement* getElement() const {return m_root;}
173 vector<const XMLCh*> m_protocolEnum;
174 vector<const IKeyDescriptor*> m_keys;
177 const EntityDescriptor* m_provider;
178 const DOMElement* m_root;
179 XMLCh* m_protocolEnumCopy;
182 vector<const IContactPerson*> m_contacts;
186 class Endpoint : public virtual IEndpoint
189 Endpoint(const DOMElement* e) : m_root(e),
190 m_binding(e->getAttributeNS(NULL,L(Binding))),
191 m_location(e->getAttributeNS(NULL,L(Location))),
192 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
193 Endpoint(const XMLCh* binding, const XMLCh* loc)
194 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
197 const XMLCh* getBinding() const { return m_binding; }
198 const XMLCh* getLocation() const { return m_location; }
199 const XMLCh* getResponseLocation() const { return m_resploc; }
200 const DOMElement* getElement() const { return m_root; }
203 const DOMElement* m_root;
204 const XMLCh* m_binding;
205 const XMLCh* m_location;
206 const XMLCh* m_resploc;
209 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
212 IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
213 unsigned short getIndex() const {return m_index;}
216 unsigned short m_index;
219 class EndpointManager : public IEndpointManager
222 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
224 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
225 delete const_cast<IEndpoint*>(*i);
227 saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
228 const IEndpoint* getDefaultEndpoint() const {
229 if (m_hard) return m_hard;
230 if (m_soft) return m_soft;
231 if (!m_endpoints.empty()) return *(m_endpoints.begin());
234 const IEndpoint* getEndpointByIndex(unsigned short index) const {
235 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
236 const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
237 if (temp && index==temp->getIndex())
242 const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
243 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
244 if (!XMLString::compareString(binding,(*i)->getBinding()))
248 void add(IEndpoint* e) {
249 m_endpoints.push_back(e);
250 if (!m_hard && e->getElement()) {
251 const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
252 if (v && (*v==chDigit_1 || *v==chLatin_t)) // explicit default
254 else if ((!v || !*v) && !m_soft) // implicit default
257 else if (!m_hard && !m_soft) {
258 // No default yet, so this one qualifies as an implicit.
264 vector<const IEndpoint*> m_endpoints;
265 const IEndpoint* m_soft; // Soft default (not explicit)
266 const IEndpoint* m_hard; // Hard default (explicit)
269 class SSORole : public Role, public virtual ISSODescriptor
272 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
274 const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
275 const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
276 const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
277 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
280 EndpointManager m_artifact,m_logout,m_nameid;
281 vector<const XMLCh*> m_formats;
284 class IDPRole : public SSORole, public virtual IIDPSSODescriptor
287 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
289 bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
290 const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
291 const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
292 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
293 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
294 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
297 EndpointManager m_sso,m_mapping,m_idreq;
298 vector<const XMLCh*> m_attrprofs;
299 vector<const SAMLAttribute*> m_attrs;
300 bool m_wantAuthnRequestsSigned;
301 const XMLCh* m_sourceId;
302 friend class EntityDescriptor;
305 class AARole : public Role, public virtual IAttributeAuthorityDescriptor
308 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
310 const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
311 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
312 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
313 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
314 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
317 EndpointManager m_query,m_idreq;
318 vector<const XMLCh*> m_formats,m_attrprofs;
319 vector<const SAMLAttribute*> m_attrs;
322 class EntityDescriptor : public IExtendedEntityDescriptor
327 XMLMetadataImpl* wrapper,
328 time_t validUntil=LONG_MAX,
329 const IEntitiesDescriptor* parent=NULL
334 const XMLCh* getId() const {return m_id;}
335 bool isValid() const {return time(NULL) < m_validUntil;}
336 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
337 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
338 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
339 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
340 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
341 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
342 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
343 const IOrganization* getOrganization() const {return m_org;}
344 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
345 Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
346 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
347 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
348 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
349 const DOMElement* getElement() const {return m_root;}
352 const char* getErrorURL() const {return m_errorURL.get();}
353 time_t getValidUntil() const {return m_validUntil;}
355 const DOMElement* m_root;
356 const IEntitiesDescriptor* m_parent;
358 auto_ptr<char> m_errorURL;
359 IOrganization* m_org;
360 vector<const IContactPerson*> m_contacts;
361 vector<const IRoleDescriptor*> m_roles;
362 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
363 vector<const IKeyAuthority*> m_keyauths;
364 vector<pair<const XMLCh*,bool> > m_scopes;
368 class EntitiesDescriptor : public IExtendedEntitiesDescriptor
373 XMLMetadataImpl* wrapper,
374 time_t validUntil=LONG_MAX,
375 const IEntitiesDescriptor* parent=NULL
377 ~EntitiesDescriptor();
379 const XMLCh* getName() const {return m_name;}
380 bool isValid() const {return time(NULL) < m_validUntil;}
381 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
382 Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
383 Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
384 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
385 const DOMElement* getElement() const {return m_root;}
388 time_t getValidUntil() const {return m_validUntil;}
390 const DOMElement* m_root;
391 const IEntitiesDescriptor* m_parent;
393 vector<const IEntitiesDescriptor*> m_groups;
394 vector<const IEntityDescriptor*> m_providers;
395 vector<const IKeyAuthority*> m_keyauths;
399 XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
400 : ReloadableXMLFileImpl(pathname), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
401 XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
402 : ReloadableXMLFileImpl(e), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
406 typedef multimap<string,const EntityDescriptor*> sitemap_t;
407 typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
411 EntityDescriptor* m_rootProvider;
412 EntitiesDescriptor* m_rootGroup;
413 const XMLMetadata* m_outer;
416 class XMLMetadata : public IMetadata, public ReloadableXMLFile
419 XMLMetadata(const DOMElement* e);
420 ~XMLMetadata() {delete m_credResolver;}
422 const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
423 const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
424 const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
425 const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
426 const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
427 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
429 bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
432 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
433 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
436 bool m_exclusions,m_verify;
438 ICredResolver* m_credResolver;
442 IPlugIn* XMLMetadataFactory(const DOMElement* e)
444 auto_ptr<XMLMetadata> m(new XMLMetadata(e));
445 m->getImplementation();
449 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
451 return new XMLMetadataImpl(e,this);
454 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
456 return new XMLMetadataImpl(pathname,this);
459 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
461 const XMLCh* type=NULL;
463 // Old metadata or new?
464 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
465 type=e->getAttributeNS(NULL,SHIB_L(Type));
466 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
468 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
469 auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
471 m_emails.push_back(temp.get());
474 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
475 type=e->getAttributeNS(NULL,SHIB_L(contactType));
476 e=saml::XML::getFirstChildElement(e);
478 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company)) && e->hasChildNodes()) {
479 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
482 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName)) && e->hasChildNodes()) {
483 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
486 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName)) && e->hasChildNodes()) {
487 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
490 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress)) && e->hasChildNodes()) {
491 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
492 if (temp.get()) m_emails.push_back(temp.get());
494 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber)) && e->hasChildNodes()) {
495 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
496 if (temp.get()) m_phones.push_back(temp.get());
498 e=saml::XML::getNextSiblingElement(e);
502 if (!XMLString::compareString(type,SHIB_L(technical)))
503 m_type=IContactPerson::technical;
504 else if (!XMLString::compareString(type,SHIB_L(support)))
505 m_type=IContactPerson::support;
506 else if (!XMLString::compareString(type,SHIB_L(administrative)))
507 m_type=IContactPerson::administrative;
508 else if (!XMLString::compareString(type,SHIB_L(billing)))
509 m_type=IContactPerson::billing;
510 else if (!XMLString::compareString(type,SHIB_L(other)))
511 m_type=IContactPerson::other;
514 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
517 e=saml::XML::getFirstChildElement(e);
519 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
520 n=e->getFirstChild();
522 auto_ptr<char> name(toUTF8(n->getNodeValue()));
523 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
524 m_names[lang.get()]=name.get();
527 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
528 n=e->getFirstChild();
530 auto_ptr<char> display(toUTF8(n->getNodeValue()));
531 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
532 m_displays[lang.get()]=display.get();
535 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
536 n=e->getFirstChild();
538 auto_ptr<char> url(toUTF8(n->getNodeValue()));
539 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
540 m_urls[lang.get()]=url.get();
543 e=saml::XML::getNextSiblingElement(e);
547 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
549 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
550 e=saml::XML::getFirstChildElement(e);
552 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
553 DOMNode* n=e->getFirstChild();
554 if (n) m_size=XMLString::parseInt(n->getNodeValue());
556 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
557 DOMNode* n=e->getFirstChild();
558 if (n) m_digest=n->getNodeValue();
560 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
561 DOMNode* n=e->getFirstChild();
562 if (n) m_params=n->getNodeValue();
564 e=saml::XML::getNextSiblingElement(e);
568 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
571 saml::NDC ndc("KeyDescriptor");
573 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
575 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
578 m_klist = new DSIGKeyInfoList(NULL);
580 // Process ds:KeyInfo
581 e=saml::XML::getFirstChildElement(e);
583 // We let XMLSec hack through anything it can. This should evolve over time, or we can
584 // plug in our own KeyResolver later...
586 if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
587 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
588 "skipping ds:KeyInfo element containing unsupported children"
591 catch (XSECCryptoException& xe) {
592 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
595 // Check for encryption methods.
596 e=saml::XML::getNextSiblingElement(e);
597 while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
598 m_methods.push_back(new EncryptionMethod(e));
601 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
603 for_each(m_methods.begin(),m_methods.end(),xmltooling::cleanup<XENCEncryptionMethod>());
607 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
610 saml::NDC ndc("KeyAuthority");
612 if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
613 m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
615 // Process ds:KeyInfo children
616 e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
618 auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
620 // We let XMLSec hack through anything it can. This should evolve over time, or we can
621 // plug in our own KeyResolver later...
622 DOMElement* child=saml::XML::getFirstChildElement(e);
625 if (!klist->addXMLKeyInfo(child)) {
626 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
627 "skipped unresolvable ds:KeyInfo child element");
630 catch (XSECCryptoException& xe) {
631 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
632 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
634 child=saml::XML::getNextSiblingElement(child);
637 if (klist->getSize()>0)
638 m_klists.push_back(klist.release());
640 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
641 "skipping ds:KeyInfo with no resolvable child elements");
642 e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
646 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
648 for_each(m_klists.begin(),m_klists.end(),xmltooling::cleanup<DSIGKeyInfoList>());
651 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
652 : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
654 // Check the root element namespace. If SAML2, assume it's the std schema.
655 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
657 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
658 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
660 m_validUntil=min(m_validUntil,exp.getEpoch());
663 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
664 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
666 // Chop the protocol list into pieces...assume any whitespace can appear in between.
667 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
668 XMLCh* temp=m_protocolEnumCopy;
669 while (temp && *temp) {
671 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
674 m_protocolEnum.push_back(start);
675 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
678 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
680 m_keys.push_back(new KeyDescriptor(e));
681 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
684 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
686 m_org=new Organization(e);
688 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
690 m_contacts.push_back(new ContactPerson(e));
691 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
696 XMLMetadataImpl::Role::~Role()
700 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
701 for_each(m_keys.begin(),m_keys.end(),xmltooling::cleanup<IKeyDescriptor>());
702 for_each(m_contacts.begin(),m_contacts.end(),xmltooling::cleanup<IContactPerson>());
705 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
707 Iterator<const XMLCh*> i(m_protocolEnum);
708 while (i.hasNext()) {
709 if (!XMLString::compareString(protocol,i.next()))
715 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
716 : Role(provider,validUntil,e)
718 // Check the root element namespace. If SAML2, assume it's the std schema.
719 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
721 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
722 for (i=0; nlist && i<nlist->getLength(); i++)
723 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
725 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
726 for (i=0; nlist && i<nlist->getLength(); i++)
727 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
729 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
730 for (i=0; nlist && i<nlist->getLength(); i++)
731 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
733 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
734 for (i=0; nlist && i<nlist->getLength(); i++) {
735 DOMNode* n=nlist->item(i)->getFirstChild();
736 if (n) m_formats.push_back(n->getNodeValue());
740 // For old style, we just do SAML 1.1 compatibility with Shib handles.
741 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
742 m_formats.push_back(shibspconstants::SHIB1_NAMEID_FORMAT_URI);
746 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
747 : SSORole(provider,validUntil,e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
749 // Check the root element namespace. If SAML2, assume it's the std schema.
750 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
751 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
752 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
754 // Check for SourceID extension.
755 DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
757 ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
758 if (ext && ext->hasChildNodes())
759 m_sourceId=ext->getFirstChild()->getNodeValue();
763 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
764 for (i=0; nlist && i<nlist->getLength(); i++)
765 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
767 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
768 for (i=0; nlist && i<nlist->getLength(); i++)
769 m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
771 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
772 for (i=0; nlist && i<nlist->getLength(); i++)
773 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
775 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
776 for (i=0; nlist && i<nlist->getLength(); i++) {
777 DOMNode* n=nlist->item(i)->getFirstChild();
778 if (n) m_attrprofs.push_back(n->getNodeValue());
781 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
782 for (i=0; nlist && i<nlist->getLength(); i++) {
783 // For now, we need to convert these to plain SAML 1.1 attributes.
784 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
785 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
786 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
787 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
788 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
790 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
791 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
792 DOMNamedNodeMap* attrs = src->getAttributes();
793 for (unsigned int j=0; j<attrs->getLength(); j++)
794 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
795 while (src->hasChildNodes())
796 val->appendChild(src->getFirstChild());
797 copy->appendChild(val);
799 m_attrs.push_back(SAMLAttribute::getInstance(copy));
803 m_protocolEnum.push_back(::XML::SHIB_NS);
804 m_attrprofs.push_back(shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI);
806 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
807 for (i=0; nlist && i<nlist->getLength(); i++) {
808 // Manufacture an endpoint for the "Shib" binding.
810 new Endpoint(shibspconstants::SHIB1_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
813 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
814 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
815 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
816 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
818 e->getOwnerDocument()->createTextNode(
819 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
824 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
825 m_keys.push_back(new KeyDescriptor(kd));
830 XMLMetadataImpl::IDPRole::~IDPRole()
832 for_each(m_attrs.begin(),m_attrs.end(),xmltooling::cleanup<SAMLAttribute>());
835 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
836 : Role(provider,validUntil,e)
838 // Check the root element namespace. If SAML2, assume it's the std schema.
839 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
841 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
842 for (i=0; nlist && i<nlist->getLength(); i++)
843 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
845 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
846 for (i=0; nlist && i<nlist->getLength(); i++)
847 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
849 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
850 for (i=0; nlist && i<nlist->getLength(); i++) {
851 DOMNode* n=nlist->item(i)->getFirstChild();
852 if (n) m_formats.push_back(n->getNodeValue());
855 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
856 for (i=0; nlist && i<nlist->getLength(); i++) {
857 DOMNode* n=nlist->item(i)->getFirstChild();
858 if (n) m_attrprofs.push_back(n->getNodeValue());
861 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
862 for (i=0; nlist && i<nlist->getLength(); i++) {
863 // For now, we need to convert these to plain SAML 1.1 attributes.
864 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
865 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
866 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
867 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
868 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
870 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
871 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
872 DOMNamedNodeMap* attrs = src->getAttributes();
873 for (unsigned int j=0; j<attrs->getLength(); j++)
874 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
875 while (src->hasChildNodes())
876 val->appendChild(src->getFirstChild());
877 copy->appendChild(val);
879 m_attrs.push_back(SAMLAttribute::getInstance(copy));
883 // For old style, we just do SAML 1.1 compatibility with Shib handles.
884 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
885 m_formats.push_back(shibspconstants::SHIB1_NAMEID_FORMAT_URI);
886 m_attrprofs.push_back(shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI);
888 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
889 for (i=0; nlist && i<nlist->getLength(); i++) {
890 // Manufacture an endpoint for the SOAP binding.
894 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
898 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
899 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
900 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
901 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
903 e->getOwnerDocument()->createTextNode(
904 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
909 m_keys.push_back(new KeyDescriptor(kd));
914 XMLMetadataImpl::AARole::~AARole()
916 for_each(m_attrs.begin(),m_attrs.end(),xmltooling::cleanup<SAMLAttribute>());
919 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
920 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
921 ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
923 // Check the root element namespace. If SAML2, assume it's the std schema.
924 DOMNodeList* scopes=NULL;
925 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
926 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
928 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
929 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
931 m_validUntil=min(validUntil,exp.getEpoch());
934 DOMElement* child=saml::XML::getFirstChildElement(e);
936 // Process the various kinds of children that we care about...
937 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
938 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
940 m_keyauths.push_back(new KeyAuthority(ext));
941 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
944 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
945 m_contacts.push_back(new ContactPerson(child));
947 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
948 m_org=new Organization(child);
950 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
951 DOMNode* loc=child->getFirstChild();
954 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
957 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
958 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
959 m_roles.push_back(new IDPRole(this,m_validUntil,child));
961 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
962 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
963 m_roles.push_back(new AARole(this,m_validUntil,child));
965 child = saml::XML::getNextSiblingElement(child);
968 // Grab all the shibmd:Scope elements here and at the role level.
969 scopes=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
972 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
973 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
976 bool idp=false,aa=false; // only want to build a role once
977 DOMElement* child=saml::XML::getFirstChildElement(e);
979 // Process the various kinds of OriginSite children that we care about...
980 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
981 m_contacts.push_back(new ContactPerson(child));
983 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
984 // Create the IDP role if needed.
985 m_roles.push_back(new IDPRole(this, m_validUntil, e));
988 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
989 // Create the AA role if needed.
990 m_roles.push_back(new AARole(this, m_validUntil, e));
993 child = saml::XML::getNextSiblingElement(child);
996 // Grab all the shib:Domain elements.
997 scopes=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
1001 for (unsigned int i=0; scopes && i < scopes->getLength(); i++) {
1002 const XMLCh* dom=(scopes->item(i)->hasChildNodes()) ? scopes->item(i)->getFirstChild()->getNodeValue() : NULL;
1004 const XMLCh* regexp=static_cast<DOMElement*>(scopes->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
1006 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
1011 auto_ptr_char id(m_id);
1012 wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1014 // Look for an IdP role, and register the artifact source ID and endpoints.
1015 const IDPRole* idp=NULL;
1016 for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1017 if (idp=dynamic_cast<const IDPRole*>(*r)) {
1018 if (idp->m_sourceId) {
1019 auto_ptr_char sourceid(idp->m_sourceId);
1020 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1023 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1024 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1026 Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1027 while (locs.hasNext()) {
1028 auto_ptr_char loc(locs.next()->getLocation());
1029 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1035 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1037 const IIDPSSODescriptor* ret=NULL;
1038 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1039 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1045 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1047 const IAttributeAuthorityDescriptor* ret=NULL;
1048 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1049 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1055 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1058 for_each(m_contacts.begin(),m_contacts.end(),xmltooling::cleanup<IContactPerson>());
1059 for_each(m_roles.begin(),m_roles.end(),xmltooling::cleanup<IRoleDescriptor>());
1060 for_each(m_keyauths.begin(),m_keyauths.end(),xmltooling::cleanup<IKeyAuthority>());
1063 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1064 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1065 ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1067 // Check the root element namespace. If SAML2, assume it's the std schema.
1068 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1070 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1071 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1072 exp.parseDateTime();
1073 m_validUntil=min(validUntil,exp.getEpoch());
1076 e=saml::XML::getFirstChildElement(e);
1078 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1079 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1081 m_keyauths.push_back(new KeyAuthority(ext));
1082 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1085 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1086 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1087 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1089 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1090 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1091 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1093 e=saml::XML::getNextSiblingElement(e);
1097 e=saml::XML::getFirstChildElement(e);
1099 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1100 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1101 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1103 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1104 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1105 e=saml::XML::getNextSiblingElement(e);
1109 if (!saml::XML::isEmpty(m_name)) {
1110 auto_ptr_char n(m_name);
1111 wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1117 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1119 for_each(m_providers.begin(),m_providers.end(),xmltooling::cleanup<IEntityDescriptor>());
1120 for_each(m_groups.begin(),m_groups.end(),xmltooling::cleanup<IEntitiesDescriptor>());
1121 for_each(m_keyauths.begin(),m_keyauths.end(),xmltooling::cleanup<IKeyAuthority>());
1124 void XMLMetadataImpl::init()
1129 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1133 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1134 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1135 m_rootGroup=new EntitiesDescriptor(m_root,this);
1137 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1138 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1139 m_rootProvider=new EntityDescriptor(m_root,this);
1141 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1142 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1143 m_rootGroup=new EntitiesDescriptor(m_root,this);
1145 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1146 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1147 m_rootProvider=new EntityDescriptor(m_root,this);
1150 log.error("Construction requires a valid SAML metadata file");
1151 throw MetadataException("Construction requires a valid SAML metadata file");
1154 catch (SAMLException& e)
1156 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1157 this->~XMLMetadataImpl();
1163 log.error("Unexpected error while parsing SAML metadata");
1164 this->~XMLMetadataImpl();
1169 if (!m_rootGroup && !m_rootProvider) {
1170 log.error("Metadata file contained no valid information");
1171 throw MetadataException("Metadata file contained no valid information");
1175 XMLMetadataImpl::~XMLMetadataImpl()
1178 delete m_rootProvider;
1181 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1183 static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1184 if (e->hasAttributeNS(NULL,uri)) {
1185 // First check for explicit enablement of entities.
1186 DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1187 for (unsigned int i=0; nlist && i<nlist->getLength(); i++) {
1188 if (nlist->item(i)->hasChildNodes()) {
1189 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1191 m_set.insert(temp.get());
1196 // If there was no explicit enablement, build a set of exclusions.
1198 nlist=e->getElementsByTagName(SHIB_L(Exclude));
1199 for (unsigned int j=0; nlist && j<nlist->getLength(); j++) {
1200 if (nlist->item(j)->hasChildNodes()) {
1201 auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1203 m_set.insert(temp.get());
1209 const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1210 m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1213 DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1215 cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";
1217 r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1219 auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1224 if (!cr_type.empty()) {
1226 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1227 ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1231 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1233 throw UnsupportedExtensionException("plugin was not a credential resolver");
1236 catch (SAMLException& e) {
1237 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1242 if (m_verify && !m_credResolver) {
1243 delete m_credResolver;
1244 throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1248 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1254 saml::NDC ndc("verifySignature");
1256 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1258 DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1261 log.error("rejecting unsigned element");
1267 XSECCryptoX509* cert=NULL;
1268 Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1269 if (certs.hasNext())
1272 log.error("unable to find any certificates to use in verifying signature");
1276 static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1277 static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1279 // Load the signature.
1281 DSIGSignature* sig=NULL;
1283 sig=prov.newSignatureFromDOM(doc,sigNode);
1287 const XMLCh* URI=NULL;
1289 // Verify the signature coverage.
1290 DSIGReferenceList* refs=sig->getReferenceList();
1291 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1292 DSIGReference* ref=refs->item(0);
1295 if (!URI || !*URI || (*URI==chPound &&
1296 !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1297 DSIGTransformList* tlist=ref->getTransforms();
1298 for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
1299 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1301 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1302 tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1312 auto_ptr_char temp((URI && *URI) ? URI : null);
1313 log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1317 sig->setSigningKey(cert->clonePublicKey());
1318 if (!sig->verify()) {
1319 auto_ptr_char temp((URI && *URI) ? URI : null);
1320 log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1324 prov.releaseSignature(sig);
1326 catch(XSECException& e) {
1327 auto_ptr_char msg(e.getMsg());
1328 log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << CategoryStream::ENDLINE;
1330 prov.releaseSignature(sig);
1333 catch(XSECCryptoException& e) {
1334 log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << CategoryStream::ENDLINE;
1336 prov.releaseSignature(sig);
1341 prov.releaseSignature(sig);
1342 log.error("caught unknown exception while verifying metadata signature");
1348 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1350 if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1352 else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1355 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1356 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1357 impl->m_sites.equal_range(providerId);
1359 time_t now=time(NULL);
1360 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1361 if (now < i->second->getValidUntil())
1364 if (!strict && range.first!=range.second)
1365 return range.first->second;
1370 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1372 auto_ptr_char temp(providerId);
1373 return lookup(temp.get(),strict);
1376 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1378 time_t now=time(NULL);
1379 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1380 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1382 // Depends on type of artifact.
1383 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1385 range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1388 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1390 range=impl->m_sources.equal_range(type2->getSourceLocation());
1396 // Check exclude list.
1397 if (range.first!=range.second) {
1398 auto_ptr_char id(range.first->second->getId());
1399 if (m_exclusions && m_set.find(id.get())!=m_set.end())
1401 else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1404 for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1405 if (now < i->second->getValidUntil())
1412 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1414 if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1416 else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1419 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1420 pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1421 impl->m_groups.equal_range(name);
1423 time_t now=time(NULL);
1424 for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1425 if (now < i->second->getValidUntil())
1428 if (!strict && range.first!=range.second)
1429 return range.first->second;
1434 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1436 auto_ptr_char temp(name);
1437 return lookupGroup(temp.get(),strict);
1440 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1442 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1443 return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);