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 using namespace shibboleth;
45 using namespace log4cpp;
51 class XMLMetadataImpl : public ReloadableXMLFileImpl
54 class ContactPerson : public IContactPerson
57 ContactPerson(const DOMElement* e);
60 ContactType getType() const { return m_type; }
61 const char* getCompany() const { return m_company.get(); }
62 const char* getGivenName() const { return m_givenName.get(); }
63 const char* getSurName() const { return m_surName.get(); }
64 Iterator<string> getEmailAddresses() const { return m_emails; }
65 Iterator<string> getTelephoneNumbers() const { return m_phones; }
66 const DOMElement* getElement() const { return m_root; }
69 const DOMElement* m_root;
71 auto_ptr<char> m_givenName,m_surName,m_company;
72 vector<string> m_emails,m_phones;
75 class Organization : public IOrganization
78 Organization(const DOMElement* e);
81 const char* getName(const char* lang="en") const { return forLang(m_names,lang); }
82 const char* getDisplayName(const char* lang="en") const { return forLang(m_displays,lang); }
83 const char* getURL(const char* lang="en") const { return forLang(m_urls,lang); }
84 const DOMElement* getElement() const { return m_root; }
87 const char* forLang(const map<string,string>& m, const char* lang) const {
88 map<string,string>::const_iterator i=m.find(lang);
89 return (i==m.end()) ? NULL : i->second.c_str();
91 const DOMElement* m_root;
92 map<string,string> m_names,m_displays,m_urls;
95 class EntityDescriptor;
97 class EncryptionMethod : public XENCEncryptionMethod
100 EncryptionMethod(const DOMElement* e);
101 ~EncryptionMethod() {}
103 const XMLCh * getAlgorithm(void) const { return m_alg; }
104 const XMLCh * getDigestMethod(void) const { return m_digest; }
105 const XMLCh * getOAEPparams(void) const { return m_params; }
106 int getKeySize(void) const { return m_size; }
107 DOMElement* getElement(void) const { return const_cast<DOMElement*>(m_root); }
108 void setDigestMethod(const XMLCh * method) {throw exception();}
109 void setOAEPparams(const XMLCh * params) {throw exception();}
110 void setKeySize(int size) {throw exception();}
113 const DOMElement* m_root;
115 const XMLCh* m_digest;
116 const XMLCh* m_params;
120 class KeyDescriptor : public IKeyDescriptor
123 KeyDescriptor(const DOMElement* e);
126 KeyUse getUse() const { return m_use; }
127 DSIGKeyInfoList* getKeyInfo() const { return m_klist; }
128 saml::Iterator<const XENCEncryptionMethod*> getEncryptionMethods() const { return m_methods; }
129 const DOMElement* getElement() const { return m_root; }
132 const DOMElement* m_root;
134 mutable DSIGKeyInfoList* m_klist;
135 vector<const XENCEncryptionMethod*> m_methods;
138 class KeyAuthority : public IKeyAuthority
141 KeyAuthority(const DOMElement* e);
144 int getVerifyDepth() const { return m_depth; }
145 Iterator<DSIGKeyInfoList*> getKeyInfos() const { return m_klists; }
149 vector<DSIGKeyInfoList*> m_klists;
152 class Role : public virtual IRoleDescriptor
155 Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
159 const IEntityDescriptor* getEntityDescriptor() const {return m_provider;}
160 Iterator<const XMLCh*> getProtocolSupportEnumeration() const {return m_protocolEnum;}
161 bool hasSupport(const XMLCh* protocol) const;
162 const char* getErrorURL() const {return (m_errorURL ? m_errorURL : m_provider->getErrorURL());}
163 bool isValid() const {return time(NULL) < m_validUntil;}
164 Iterator<const IKeyDescriptor*> getKeyDescriptors() const {return m_keys;}
165 const IOrganization* getOrganization() const {return m_org ? m_org : m_provider->getOrganization();}
166 Iterator<const IContactPerson*> getContactPersons() const
167 {return (m_contacts.empty() ? m_provider->getContactPersons() : m_contacts);}
168 const DOMElement* getElement() const {return m_root;}
171 vector<const XMLCh*> m_protocolEnum;
172 vector<const IKeyDescriptor*> m_keys;
175 const EntityDescriptor* m_provider;
176 const DOMElement* m_root;
177 XMLCh* m_protocolEnumCopy;
180 vector<const IContactPerson*> m_contacts;
184 class Endpoint : public virtual IEndpoint
187 Endpoint(const DOMElement* e) : m_root(e),
188 m_binding(e->getAttributeNS(NULL,L(Binding))),
189 m_location(e->getAttributeNS(NULL,L(Location))),
190 m_resploc(e->getAttributeNS(NULL,SHIB_L(ResponseLocation))) {}
191 Endpoint(const XMLCh* binding, const XMLCh* loc)
192 : m_root(NULL), m_binding(binding), m_location(loc), m_resploc(NULL) {}
195 const XMLCh* getBinding() const { return m_binding; }
196 const XMLCh* getLocation() const { return m_location; }
197 const XMLCh* getResponseLocation() const { return m_resploc; }
198 const DOMElement* getElement() const { return m_root; }
201 const DOMElement* m_root;
202 const XMLCh* m_binding;
203 const XMLCh* m_location;
204 const XMLCh* m_resploc;
207 class IndexedEndpoint : public Endpoint, public virtual IIndexedEndpoint
210 IndexedEndpoint(const DOMElement* e) : Endpoint(e), m_index(XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(index)))) {}
211 unsigned short getIndex() const {return m_index;}
214 unsigned short m_index;
217 class EndpointManager : public IEndpointManager
220 EndpointManager() : m_soft(NULL), m_hard(NULL) {}
222 for (vector<const IEndpoint*>::iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
223 delete const_cast<IEndpoint*>(*i);
225 saml::Iterator<const IEndpoint*> getEndpoints() const {return m_endpoints;}
226 const IEndpoint* getDefaultEndpoint() const {
227 if (m_hard) return m_hard;
228 if (m_soft) return m_soft;
229 if (!m_endpoints.empty()) return *(m_endpoints.begin());
232 const IEndpoint* getEndpointByIndex(unsigned short index) const {
233 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++) {
234 const IIndexedEndpoint* temp=dynamic_cast<const IIndexedEndpoint*>(*i);
235 if (temp && index==temp->getIndex())
240 const IEndpoint* getEndpointByBinding(const XMLCh* binding) const {
241 for (vector<const IEndpoint*>::const_iterator i=m_endpoints.begin(); i!=m_endpoints.end(); i++)
242 if (!XMLString::compareString(binding,(*i)->getBinding()))
246 void add(IEndpoint* e) {
247 m_endpoints.push_back(e);
248 if (!m_hard && e->getElement()) {
249 const XMLCh* v=e->getElement()->getAttributeNS(NULL,SHIB_L(isDefault));
250 if (v && (*v==chDigit_1 || *v==chLatin_t)) // explicit default
252 else if ((!v || !*v) && !m_soft) // implicit default
255 else if (!m_hard && !m_soft) {
256 // No default yet, so this one qualifies as an implicit.
262 vector<const IEndpoint*> m_endpoints;
263 const IEndpoint* m_soft; // Soft default (not explicit)
264 const IEndpoint* m_hard; // Hard default (explicit)
267 class SSORole : public Role, public virtual ISSODescriptor
270 SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
272 const IEndpointManager* getArtifactResolutionServiceManager() const {return &m_artifact;}
273 const IEndpointManager* getSingleLogoutServiceManager() const {return &m_logout;}
274 const IEndpointManager* getManageNameIDServiceManager() const {return &m_nameid;}
275 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
278 EndpointManager m_artifact,m_logout,m_nameid;
279 vector<const XMLCh*> m_formats;
282 class IDPRole : public SSORole, public virtual IIDPSSODescriptor
285 IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
287 bool getWantAuthnRequestsSigned() const {return m_wantAuthnRequestsSigned;}
288 const IEndpointManager* getSingleSignOnServiceManager() const {return &m_sso;}
289 const IEndpointManager* getNameIDMappingServiceManager() const {return &m_mapping;}
290 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
291 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
292 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
295 EndpointManager m_sso,m_mapping,m_idreq;
296 vector<const XMLCh*> m_attrprofs;
297 vector<const SAMLAttribute*> m_attrs;
298 bool m_wantAuthnRequestsSigned;
299 const XMLCh* m_sourceId;
300 friend class EntityDescriptor;
303 class AARole : public Role, public virtual IAttributeAuthorityDescriptor
306 AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e);
308 const IEndpointManager* getAttributeServiceManager() const {return &m_query;}
309 const IEndpointManager* getAssertionIDRequestServiceManager() const {return &m_idreq;}
310 saml::Iterator<const XMLCh*> getNameIDFormats() const {return m_formats;}
311 saml::Iterator<const XMLCh*> getAttributeProfiles() const {return m_attrprofs;}
312 saml::Iterator<const saml::SAMLAttribute*> getAttributes() const {return m_attrs;}
315 EndpointManager m_query,m_idreq;
316 vector<const XMLCh*> m_formats,m_attrprofs;
317 vector<const SAMLAttribute*> m_attrs;
320 class EntityDescriptor : public IExtendedEntityDescriptor
325 XMLMetadataImpl* wrapper,
326 time_t validUntil=LONG_MAX,
327 const IEntitiesDescriptor* parent=NULL
332 const XMLCh* getId() const {return m_id;}
333 bool isValid() const {return time(NULL) < m_validUntil;}
334 Iterator<const IRoleDescriptor*> getRoleDescriptors() const {return m_roles;}
335 const IIDPSSODescriptor* getIDPSSODescriptor(const XMLCh* protocol) const;
336 const ISPSSODescriptor* getSPSSODescriptor(const XMLCh* protocol) const {return NULL;}
337 const IAuthnAuthorityDescriptor* getAuthnAuthorityDescriptor(const XMLCh* protocol) const {return NULL;}
338 const IAttributeAuthorityDescriptor* getAttributeAuthorityDescriptor(const XMLCh* protocol) const;
339 const IPDPDescriptor* getPDPDescriptor(const XMLCh* protocol) const {return NULL;}
340 const IAffiliationDescriptor* getAffiliationDescriptor() const {return NULL;}
341 const IOrganization* getOrganization() const {return m_org;}
342 Iterator<const IContactPerson*> getContactPersons() const {return m_contacts;}
343 Iterator<pair<const XMLCh*,const XMLCh*> > getAdditionalMetadataLocations() const {return m_locs;}
344 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
345 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
346 saml::Iterator<std::pair<const XMLCh*,bool> > getScopes() const {return m_scopes;}
347 const DOMElement* getElement() const {return m_root;}
350 const char* getErrorURL() const {return m_errorURL.get();}
351 time_t getValidUntil() const {return m_validUntil;}
353 const DOMElement* m_root;
354 const IEntitiesDescriptor* m_parent;
356 auto_ptr<char> m_errorURL;
357 IOrganization* m_org;
358 vector<const IContactPerson*> m_contacts;
359 vector<const IRoleDescriptor*> m_roles;
360 vector<pair<const XMLCh*,const XMLCh*> > m_locs;
361 vector<const IKeyAuthority*> m_keyauths;
362 vector<pair<const XMLCh*,bool> > m_scopes;
366 class EntitiesDescriptor : public IExtendedEntitiesDescriptor
371 XMLMetadataImpl* wrapper,
372 time_t validUntil=LONG_MAX,
373 const IEntitiesDescriptor* parent=NULL
375 ~EntitiesDescriptor();
377 const XMLCh* getName() const {return m_name;}
378 bool isValid() const {return time(NULL) < m_validUntil;}
379 const IEntitiesDescriptor* getEntitiesDescriptor() const {return m_parent;}
380 Iterator<const IEntitiesDescriptor*> getEntitiesDescriptors() const {return m_groups;}
381 Iterator<const IEntityDescriptor*> getEntityDescriptors() const {return m_providers;}
382 Iterator<const IKeyAuthority*> getKeyAuthorities() const {return m_keyauths;}
383 const DOMElement* getElement() const {return m_root;}
386 time_t getValidUntil() const {return m_validUntil;}
388 const DOMElement* m_root;
389 const IEntitiesDescriptor* m_parent;
391 vector<const IEntitiesDescriptor*> m_groups;
392 vector<const IEntityDescriptor*> m_providers;
393 vector<const IKeyAuthority*> m_keyauths;
397 XMLMetadataImpl(const char* pathname, const XMLMetadata* wrapper)
398 : ReloadableXMLFileImpl(pathname), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
399 XMLMetadataImpl(const DOMElement* e, const XMLMetadata* wrapper)
400 : ReloadableXMLFileImpl(e), m_outer(wrapper), m_rootProvider(NULL), m_rootGroup(NULL) { init(); }
404 typedef multimap<string,const EntityDescriptor*> sitemap_t;
405 typedef multimap<string,const EntitiesDescriptor*> groupmap_t;
409 EntityDescriptor* m_rootProvider;
410 EntitiesDescriptor* m_rootGroup;
411 const XMLMetadata* m_outer;
414 class XMLMetadata : public IMetadata, public ReloadableXMLFile
417 XMLMetadata(const DOMElement* e);
418 ~XMLMetadata() {delete m_credResolver;}
420 const IEntityDescriptor* lookup(const char* providerId, bool strict=true) const;
421 const IEntityDescriptor* lookup(const XMLCh* providerId, bool strict=true) const;
422 const IEntityDescriptor* lookup(const saml::SAMLArtifact* artifact) const;
423 const IEntitiesDescriptor* lookupGroup(const char* name, bool strict=true) const;
424 const IEntitiesDescriptor* lookupGroup(const XMLCh* name, bool strict=true) const;
425 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> getRoot() const;
427 bool verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const;
430 virtual ReloadableXMLFileImpl* newImplementation(const char* pathname, bool first=true) const;
431 virtual ReloadableXMLFileImpl* newImplementation(const DOMElement* e, bool first=true) const;
434 bool m_exclusions,m_verify;
436 ICredResolver* m_credResolver;
440 IPlugIn* XMLMetadataFactory(const DOMElement* e)
442 auto_ptr<XMLMetadata> m(new XMLMetadata(e));
443 m->getImplementation();
447 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const DOMElement* e, bool first) const
449 return new XMLMetadataImpl(e,this);
452 ReloadableXMLFileImpl* XMLMetadata::newImplementation(const char* pathname, bool first) const
454 return new XMLMetadataImpl(pathname,this);
457 XMLMetadataImpl::ContactPerson::ContactPerson(const DOMElement* e) : m_root(e)
459 const XMLCh* type=NULL;
461 // Old metadata or new?
462 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(Contact))) {
463 type=e->getAttributeNS(NULL,SHIB_L(Type));
464 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(Name))));
466 if (e->hasAttributeNS(NULL,SHIB_L(Email))) {
467 auto_ptr<char> temp(toUTF8(e->getAttributeNS(NULL,SHIB_L(Email))));
469 m_emails.push_back(temp.get());
472 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
473 type=e->getAttributeNS(NULL,SHIB_L(contactType));
474 e=saml::XML::getFirstChildElement(e);
476 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Company)) && e->hasChildNodes()) {
477 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
480 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(GivenName)) && e->hasChildNodes()) {
481 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
484 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(SurName)) && e->hasChildNodes()) {
485 auto_ptr<char> wrapper(toUTF8(e->getFirstChild()->getNodeValue()));
488 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EmailAddress)) && e->hasChildNodes()) {
489 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
490 if (temp.get()) m_emails.push_back(temp.get());
492 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(TelephoneNumber)) && e->hasChildNodes()) {
493 auto_ptr<char> temp(toUTF8(e->getFirstChild()->getNodeValue()));
494 if (temp.get()) m_phones.push_back(temp.get());
496 e=saml::XML::getNextSiblingElement(e);
500 if (!XMLString::compareString(type,SHIB_L(technical)))
501 m_type=IContactPerson::technical;
502 else if (!XMLString::compareString(type,SHIB_L(support)))
503 m_type=IContactPerson::support;
504 else if (!XMLString::compareString(type,SHIB_L(administrative)))
505 m_type=IContactPerson::administrative;
506 else if (!XMLString::compareString(type,SHIB_L(billing)))
507 m_type=IContactPerson::billing;
508 else if (!XMLString::compareString(type,SHIB_L(other)))
509 m_type=IContactPerson::other;
512 XMLMetadataImpl::Organization::Organization(const DOMElement* e) : m_root(e)
515 e=saml::XML::getFirstChildElement(e);
517 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationName))) {
518 n=e->getFirstChild();
520 auto_ptr<char> name(toUTF8(n->getNodeValue()));
521 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
522 m_names[lang.get()]=name.get();
525 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationDisplayName))) {
526 n=e->getFirstChild();
528 auto_ptr<char> display(toUTF8(n->getNodeValue()));
529 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
530 m_displays[lang.get()]=display.get();
533 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(OrganizationURL))) {
534 n=e->getFirstChild();
536 auto_ptr<char> url(toUTF8(n->getNodeValue()));
537 auto_ptr_char lang(e->getAttributeNS(saml::XML::XML_NS,L(lang)));
538 m_urls[lang.get()]=url.get();
541 e=saml::XML::getNextSiblingElement(e);
545 XMLMetadataImpl::EncryptionMethod::EncryptionMethod(const DOMElement* e) : m_root(e)
547 m_alg=e->getAttributeNS(NULL,SHIB_L(Algorithm));
548 e=saml::XML::getFirstChildElement(e);
550 if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(KeySize))) {
551 DOMNode* n=e->getFirstChild();
552 if (n) m_size=XMLString::parseInt(n->getNodeValue());
554 else if (saml::XML::isElementNamed(e,saml::XML::XMLSIG_NS,SHIB_L(DigestMethod))) {
555 DOMNode* n=e->getFirstChild();
556 if (n) m_digest=n->getNodeValue();
558 else if (saml::XML::isElementNamed(e,::XML::XMLENC_NS,SHIB_L(OAEParams))) {
559 DOMNode* n=e->getFirstChild();
560 if (n) m_params=n->getNodeValue();
562 e=saml::XML::getNextSiblingElement(e);
566 XMLMetadataImpl::KeyDescriptor::KeyDescriptor(const DOMElement* e) : m_root(e), m_use(unspecified), m_klist(NULL)
569 saml::NDC ndc("KeyDescriptor");
571 if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(encryption)))
573 else if (!XMLString::compareString(e->getAttributeNS(NULL,SHIB_L(use)),SHIB_L(signing)))
576 m_klist = new DSIGKeyInfoList(NULL);
578 // Process ds:KeyInfo
579 e=saml::XML::getFirstChildElement(e);
581 // We let XMLSec hack through anything it can. This should evolve over time, or we can
582 // plug in our own KeyResolver later...
584 if (!m_klist->loadListFromXML(const_cast<DOMElement*>(e)))
585 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
586 "skipping ds:KeyInfo element containing unsupported children"
589 catch (XSECCryptoException& xe) {
590 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("unable to process ds:KeyInfo element: %s",xe.getMsg());
593 // Check for encryption methods.
594 e=saml::XML::getNextSiblingElement(e);
595 while (e && saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EncryptionMethod)))
596 m_methods.push_back(new EncryptionMethod(e));
599 XMLMetadataImpl::KeyDescriptor::~KeyDescriptor()
601 for_each(m_methods.begin(),m_methods.end(),xmltooling::cleanup<XENCEncryptionMethod>());
605 XMLMetadataImpl::KeyAuthority::KeyAuthority(const DOMElement* e) : m_depth(1)
608 saml::NDC ndc("KeyAuthority");
610 if (e->hasAttributeNS(NULL,SHIB_L(VerifyDepth)))
611 m_depth=XMLString::parseInt(e->getAttributeNS(NULL,SHIB_L(VerifyDepth)));
613 // Process ds:KeyInfo children
614 e=saml::XML::getFirstChildElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
616 auto_ptr<DSIGKeyInfoList> klist(new DSIGKeyInfoList(NULL));
618 // We let XMLSec hack through anything it can. This should evolve over time, or we can
619 // plug in our own KeyResolver later...
620 DOMElement* child=saml::XML::getFirstChildElement(e);
623 if (!klist->addXMLKeyInfo(child)) {
624 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
625 "skipped unresolvable ds:KeyInfo child element");
628 catch (XSECCryptoException& xe) {
629 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error(
630 "unable to process ds:KeyInfo child element: %s",xe.getMsg());
632 child=saml::XML::getNextSiblingElement(child);
635 if (klist->getSize()>0)
636 m_klists.push_back(klist.release());
638 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").warn(
639 "skipping ds:KeyInfo with no resolvable child elements");
640 e=saml::XML::getNextSiblingElement(e,saml::XML::XMLSIG_NS,L(KeyInfo));
644 XMLMetadataImpl::KeyAuthority::~KeyAuthority()
646 for_each(m_klists.begin(),m_klists.end(),xmltooling::cleanup<DSIGKeyInfoList>());
649 XMLMetadataImpl::Role::Role(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
650 : m_provider(provider), m_errorURL(NULL), m_protocolEnumCopy(NULL), m_org(NULL), m_validUntil(validUntil), m_root(e)
652 // Check the root element namespace. If SAML2, assume it's the std schema.
653 if (e && !XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
655 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
656 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
658 m_validUntil=min(m_validUntil,exp.getEpoch());
661 if (e->hasAttributeNS(NULL,SHIB_L(errorURL)))
662 m_errorURL=toUTF8(e->getAttributeNS(NULL,SHIB_L(errorURL)));
664 // Chop the protocol list into pieces...assume any whitespace can appear in between.
665 m_protocolEnumCopy=XMLString::replicate(e->getAttributeNS(NULL,SHIB_L(protocolSupportEnumeration)));
666 XMLCh* temp=m_protocolEnumCopy;
667 while (temp && *temp) {
669 while (*temp && !XMLChar1_1::isWhitespace(*temp)) temp++;
672 m_protocolEnum.push_back(start);
673 while (*temp && XMLChar1_1::isWhitespace(*temp)) temp++;
676 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
678 m_keys.push_back(new KeyDescriptor(e));
679 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
682 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(Organization));
684 m_org=new Organization(e);
686 e=saml::XML::getFirstChildElement(m_root,::XML::SAML2META_NS,SHIB_L(ContactPerson));
688 m_contacts.push_back(new ContactPerson(e));
689 e=saml::XML::getNextSiblingElement(e,::XML::SAML2META_NS,SHIB_L(ContactPerson));
694 XMLMetadataImpl::Role::~Role()
698 if (m_protocolEnumCopy) XMLString::release(&m_protocolEnumCopy);
699 for_each(m_keys.begin(),m_keys.end(),xmltooling::cleanup<IKeyDescriptor>());
700 for_each(m_contacts.begin(),m_contacts.end(),xmltooling::cleanup<IContactPerson>());
703 bool XMLMetadataImpl::Role::hasSupport(const XMLCh* protocol) const
705 Iterator<const XMLCh*> i(m_protocolEnum);
706 while (i.hasNext()) {
707 if (!XMLString::compareString(protocol,i.next()))
713 XMLMetadataImpl::SSORole::SSORole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
714 : Role(provider,validUntil,e)
716 // Check the root element namespace. If SAML2, assume it's the std schema.
717 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
719 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ArtifactResolutionService));
720 for (i=0; nlist && i<nlist->getLength(); i++)
721 m_artifact.add(new IndexedEndpoint(static_cast<DOMElement*>(nlist->item(i))));
723 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleLogoutService));
724 for (i=0; nlist && i<nlist->getLength(); i++)
725 m_logout.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
727 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(ManageNameIDService));
728 for (i=0; nlist && i<nlist->getLength(); i++)
729 m_nameid.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
731 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
732 for (i=0; nlist && i<nlist->getLength(); i++) {
733 DOMNode* n=nlist->item(i)->getFirstChild();
734 if (n) m_formats.push_back(n->getNodeValue());
738 // For old style, we just do SAML 1.1 compatibility with Shib handles.
739 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
740 m_formats.push_back(shibboleth::Constants::SHIB_NAMEID_FORMAT_URI);
744 XMLMetadataImpl::IDPRole::IDPRole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
745 : SSORole(provider,validUntil,e), m_wantAuthnRequestsSigned(false), m_sourceId(NULL)
747 // Check the root element namespace. If SAML2, assume it's the std schema.
748 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
749 const XMLCh* flag=e->getAttributeNS(NULL,SHIB_L(WantAuthnRequestsSigned));
750 m_wantAuthnRequestsSigned=(flag && (*flag==chDigit_1 || *flag==chLatin_t));
752 // Check for SourceID extension.
753 DOMElement* ext=saml::XML::getFirstChildElement(e,::XML::SAML2META_NS,SHIB_L(Extensions));
755 ext=saml::XML::getFirstChildElement(ext,saml::XML::SAML_ARTIFACT_SOURCEID,SHIB_L(SourceID));
756 if (ext && ext->hasChildNodes())
757 m_sourceId=ext->getFirstChild()->getNodeValue();
761 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(SingleSignOnService));
762 for (i=0; nlist && i<nlist->getLength(); i++)
763 m_sso.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
765 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDMappingService));
766 for (i=0; nlist && i<nlist->getLength(); i++)
767 m_mapping.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
769 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
770 for (i=0; nlist && i<nlist->getLength(); i++)
771 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
773 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
774 for (i=0; nlist && i<nlist->getLength(); i++) {
775 DOMNode* n=nlist->item(i)->getFirstChild();
776 if (n) m_attrprofs.push_back(n->getNodeValue());
779 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
780 for (i=0; nlist && i<nlist->getLength(); i++) {
781 // For now, we need to convert these to plain SAML 1.1 attributes.
782 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
783 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
784 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
785 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
786 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
788 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
789 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
790 DOMNamedNodeMap* attrs = src->getAttributes();
791 for (unsigned int j=0; j<attrs->getLength(); j++)
792 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
793 while (src->hasChildNodes())
794 val->appendChild(src->getFirstChild());
795 copy->appendChild(val);
797 m_attrs.push_back(SAMLAttribute::getInstance(copy));
801 m_protocolEnum.push_back(Constants::SHIB_NS);
802 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
804 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(HandleService));
805 for (i=0; nlist && i<nlist->getLength(); i++) {
806 // Manufacture an endpoint for the "Shib" binding.
808 new Endpoint(Constants::SHIB_AUTHNREQUEST_PROFILE_URI,static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location)))
811 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
812 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
813 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
814 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
816 e->getOwnerDocument()->createTextNode(
817 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
822 kd->setAttributeNS(NULL,SHIB_L(use),SHIB_L(signing));
823 m_keys.push_back(new KeyDescriptor(kd));
828 XMLMetadataImpl::IDPRole::~IDPRole()
830 for_each(m_attrs.begin(),m_attrs.end(),xmltooling::cleanup<SAMLAttribute>());
833 XMLMetadataImpl::AARole::AARole(const EntityDescriptor* provider, time_t validUntil, const DOMElement* e)
834 : Role(provider,validUntil,e)
836 // Check the root element namespace. If SAML2, assume it's the std schema.
837 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
839 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeService));
840 for (i=0; nlist && i<nlist->getLength(); i++)
841 m_query.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
843 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AssertionIDRequestService));
844 for (i=0; nlist && i<nlist->getLength(); i++)
845 m_idreq.add(new Endpoint(static_cast<DOMElement*>(nlist->item(i))));
847 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(NameIDFormat));
848 for (i=0; nlist && i<nlist->getLength(); i++) {
849 DOMNode* n=nlist->item(i)->getFirstChild();
850 if (n) m_formats.push_back(n->getNodeValue());
853 nlist=e->getElementsByTagNameNS(::XML::SAML2META_NS,SHIB_L(AttributeProfile));
854 for (i=0; nlist && i<nlist->getLength(); i++) {
855 DOMNode* n=nlist->item(i)->getFirstChild();
856 if (n) m_attrprofs.push_back(n->getNodeValue());
859 nlist=e->getElementsByTagNameNS(::XML::SAML2ASSERT_NS,L(Attribute));
860 for (i=0; nlist && i<nlist->getLength(); i++) {
861 // For now, we need to convert these to plain SAML 1.1 attributes.
862 DOMElement* src=static_cast<DOMElement*>(nlist->item(i));
863 DOMElement* copy=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(Attribute));
864 copy->setAttributeNS(NULL,L(AttributeName),src->getAttributeNS(NULL,SHIB_L(Name)));
865 copy->setAttributeNS(NULL,L(AttributeNamespace),src->getAttributeNS(NULL,SHIB_L(NameFormat)));
866 src=saml::XML::getFirstChildElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
868 src=saml::XML::getNextSiblingElement(src,::XML::SAML2ASSERT_NS,L(AttributeValue));
869 DOMElement* val=e->getOwnerDocument()->createElementNS(saml::XML::SAML_NS,L(AttributeValue));
870 DOMNamedNodeMap* attrs = src->getAttributes();
871 for (unsigned int j=0; j<attrs->getLength(); j++)
872 val->setAttributeNodeNS(static_cast<DOMAttr*>(e->getOwnerDocument()->importNode(attrs->item(j),true)));
873 while (src->hasChildNodes())
874 val->appendChild(src->getFirstChild());
875 copy->appendChild(val);
877 m_attrs.push_back(SAMLAttribute::getInstance(copy));
881 // For old style, we just do SAML 1.1 compatibility with Shib handles.
882 m_protocolEnum.push_back(saml::XML::SAML11_PROTOCOL_ENUM);
883 m_formats.push_back(Constants::SHIB_NAMEID_FORMAT_URI);
884 m_attrprofs.push_back(Constants::SHIB_ATTRIBUTE_NAMESPACE_URI);
886 DOMNodeList* nlist=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(AttributeAuthority));
887 for (i=0; nlist && i<nlist->getLength(); i++) {
888 // Manufacture an endpoint for the SOAP binding.
892 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,L(Location))
896 // We're going to "mock up" a KeyDescriptor that contains the specified Name as a ds:KeyName.
897 DOMElement* kd=e->getOwnerDocument()->createElementNS(::XML::SAML2META_NS,SHIB_L(KeyDescriptor));
898 DOMElement* ki=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,L(KeyInfo));
899 DOMElement* kn=e->getOwnerDocument()->createElementNS(saml::XML::XMLSIG_NS,SHIB_L(KeyName));
901 e->getOwnerDocument()->createTextNode(
902 static_cast<DOMElement*>(nlist->item(i))->getAttributeNS(NULL,SHIB_L(Name))
907 m_keys.push_back(new KeyDescriptor(kd));
912 XMLMetadataImpl::AARole::~AARole()
914 for_each(m_attrs.begin(),m_attrs.end(),xmltooling::cleanup<SAMLAttribute>());
917 XMLMetadataImpl::EntityDescriptor::EntityDescriptor(
918 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
919 ) : m_root(e), m_parent(parent), m_org(NULL), m_validUntil(validUntil)
921 // Check the root element namespace. If SAML2, assume it's the std schema.
922 DOMNodeList* scopes=NULL;
923 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
924 m_id=e->getAttributeNS(NULL,SHIB_L(entityID));
926 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
927 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
929 m_validUntil=min(validUntil,exp.getEpoch());
932 DOMElement* child=saml::XML::getFirstChildElement(e);
934 // Process the various kinds of children that we care about...
935 if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Extensions))) {
936 DOMElement* ext = saml::XML::getFirstChildElement(child,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
938 m_keyauths.push_back(new KeyAuthority(ext));
939 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
942 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(ContactPerson))) {
943 m_contacts.push_back(new ContactPerson(child));
945 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(Organization))) {
946 m_org=new Organization(child);
948 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AdditionalMetadataLocation))) {
949 DOMNode* loc=child->getFirstChild();
952 pair<const XMLCh*,const XMLCh*>(child->getAttributeNS(NULL,::XML::Literals::_namespace),loc->getNodeValue())
955 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(IDPSSODescriptor))) {
956 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
957 m_roles.push_back(new IDPRole(this,m_validUntil,child));
959 else if (saml::XML::isElementNamed(child,::XML::SAML2META_NS,SHIB_L(AttributeAuthorityDescriptor))) {
960 if (wrapper->m_outer->verifySignature(child->getOwnerDocument(),child,false))
961 m_roles.push_back(new AARole(this,m_validUntil,child));
963 child = saml::XML::getNextSiblingElement(child);
966 // Grab all the shibmd:Scope elements here and at the role level.
967 scopes=e->getElementsByTagNameNS(::XML::SHIBMETA_NS,SHIB_L(Scope));
970 m_id=e->getAttributeNS(NULL,SHIB_L(Name));
971 auto_ptr<char> wrapper(toUTF8(e->getAttributeNS(NULL,SHIB_L(ErrorURL))));
974 bool idp=false,aa=false; // only want to build a role once
975 DOMElement* child=saml::XML::getFirstChildElement(e);
977 // Process the various kinds of OriginSite children that we care about...
978 if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(Contact))) {
979 m_contacts.push_back(new ContactPerson(child));
981 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(HandleService)) && !idp) {
982 // Create the IDP role if needed.
983 m_roles.push_back(new IDPRole(this, m_validUntil, e));
986 else if (saml::XML::isElementNamed(child,::XML::SHIB_NS,SHIB_L(AttributeAuthority)) && !aa) {
987 // Create the AA role if needed.
988 m_roles.push_back(new AARole(this, m_validUntil, e));
991 child = saml::XML::getNextSiblingElement(child);
994 // Grab all the shib:Domain elements.
995 scopes=e->getElementsByTagNameNS(::XML::SHIB_NS,SHIB_L(Domain));
999 for (unsigned int i=0; scopes && i < scopes->getLength(); i++) {
1000 const XMLCh* dom=(scopes->item(i)->hasChildNodes()) ? scopes->item(i)->getFirstChild()->getNodeValue() : NULL;
1002 const XMLCh* regexp=static_cast<DOMElement*>(scopes->item(i))->getAttributeNS(NULL,SHIB_L(regexp));
1004 pair<const XMLCh*,bool>(dom,(regexp && (*regexp==chLatin_t || *regexp==chDigit_1)))
1009 auto_ptr_char id(m_id);
1010 wrapper->m_sites.insert(pair<const string,const EntityDescriptor*>(id.get(),this));
1012 // Look for an IdP role, and register the artifact source ID and endpoints.
1013 const IDPRole* idp=NULL;
1014 for (vector<const IRoleDescriptor*>::const_iterator r=m_roles.begin(); r!=m_roles.end(); r++) {
1015 if (idp=dynamic_cast<const IDPRole*>(*r)) {
1016 if (idp->m_sourceId) {
1017 auto_ptr_char sourceid(idp->m_sourceId);
1018 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid.get(),this));
1021 string sourceid=SAMLArtifact::toHex(SAMLArtifactType0001::generateSourceId(id.get()));
1022 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(sourceid,this));
1024 Iterator<const IEndpoint*> locs=idp->getArtifactResolutionServiceManager()->getEndpoints();
1025 while (locs.hasNext()) {
1026 auto_ptr_char loc(locs.next()->getLocation());
1027 wrapper->m_sources.insert(pair<const string,const EntityDescriptor*>(loc.get(),this));
1033 const IIDPSSODescriptor* XMLMetadataImpl::EntityDescriptor::getIDPSSODescriptor(const XMLCh* protocol) const
1035 const IIDPSSODescriptor* ret=NULL;
1036 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1037 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IIDPSSODescriptor*>(*i)))
1043 const IAttributeAuthorityDescriptor* XMLMetadataImpl::EntityDescriptor::getAttributeAuthorityDescriptor(const XMLCh* protocol) const
1045 const IAttributeAuthorityDescriptor* ret=NULL;
1046 for (vector<const IRoleDescriptor*>::const_iterator i=m_roles.begin(); i!=m_roles.end(); i++) {
1047 if ((*i)->hasSupport(protocol) && (*i)->isValid() && (ret=dynamic_cast<const IAttributeAuthorityDescriptor*>(*i)))
1053 XMLMetadataImpl::EntityDescriptor::~EntityDescriptor()
1056 for_each(m_contacts.begin(),m_contacts.end(),xmltooling::cleanup<IContactPerson>());
1057 for_each(m_roles.begin(),m_roles.end(),xmltooling::cleanup<IRoleDescriptor>());
1058 for_each(m_keyauths.begin(),m_keyauths.end(),xmltooling::cleanup<IKeyAuthority>());
1061 XMLMetadataImpl::EntitiesDescriptor::EntitiesDescriptor(
1062 const DOMElement* e, XMLMetadataImpl* wrapper, time_t validUntil, const IEntitiesDescriptor* parent
1063 ) : m_root(e), m_name(e->getAttributeNS(NULL,SHIB_L(Name))), m_parent(parent), m_validUntil(validUntil)
1065 // Check the root element namespace. If SAML2, assume it's the std schema.
1066 if (!XMLString::compareString(e->getNamespaceURI(),::XML::SAML2META_NS)) {
1068 if (e->hasAttributeNS(NULL,SHIB_L(validUntil))) {
1069 SAMLDateTime exp(e->getAttributeNS(NULL,SHIB_L(validUntil)));
1070 exp.parseDateTime();
1071 m_validUntil=min(validUntil,exp.getEpoch());
1074 e=saml::XML::getFirstChildElement(e);
1076 if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(Extensions))) {
1077 DOMElement* ext = saml::XML::getFirstChildElement(e,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1079 m_keyauths.push_back(new KeyAuthority(ext));
1080 ext = saml::XML::getNextSiblingElement(ext,::XML::SHIBMETA_NS,SHIB_L(KeyAuthority));
1083 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1084 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1085 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1087 else if (saml::XML::isElementNamed(e,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1088 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1089 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1091 e=saml::XML::getNextSiblingElement(e);
1095 e=saml::XML::getFirstChildElement(e);
1097 if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1098 if (wrapper->m_outer->verifySignature(e->getOwnerDocument(),e,false))
1099 m_groups.push_back(new EntitiesDescriptor(e,wrapper,m_validUntil,this));
1101 else if (saml::XML::isElementNamed(e,::XML::SHIB_NS,SHIB_L(OriginSite)))
1102 m_providers.push_back(new EntityDescriptor(e,wrapper,m_validUntil,this));
1103 e=saml::XML::getNextSiblingElement(e);
1107 if (!saml::XML::isEmpty(m_name)) {
1108 auto_ptr_char n(m_name);
1109 wrapper->m_groups.insert(pair<const string,const EntitiesDescriptor*>(n.get(),this));
1115 XMLMetadataImpl::EntitiesDescriptor::~EntitiesDescriptor()
1117 for_each(m_providers.begin(),m_providers.end(),xmltooling::cleanup<IEntityDescriptor>());
1118 for_each(m_groups.begin(),m_groups.end(),xmltooling::cleanup<IEntitiesDescriptor>());
1119 for_each(m_keyauths.begin(),m_keyauths.end(),xmltooling::cleanup<IKeyAuthority>());
1122 void XMLMetadataImpl::init()
1127 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1131 if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntitiesDescriptor))) {
1132 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1133 m_rootGroup=new EntitiesDescriptor(m_root,this);
1135 else if (saml::XML::isElementNamed(m_root,::XML::SAML2META_NS,SHIB_L(EntityDescriptor))) {
1136 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1137 m_rootProvider=new EntityDescriptor(m_root,this);
1139 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(SiteGroup))) {
1140 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1141 m_rootGroup=new EntitiesDescriptor(m_root,this);
1143 else if (saml::XML::isElementNamed(m_root,::XML::SHIB_NS,SHIB_L(OriginSite))) {
1144 if (m_outer->verifySignature(m_root->getOwnerDocument(),m_root,true))
1145 m_rootProvider=new EntityDescriptor(m_root,this);
1148 log.error("Construction requires a valid SAML metadata file");
1149 throw MetadataException("Construction requires a valid SAML metadata file");
1152 catch (SAMLException& e)
1154 log.errorStream() << "Error while parsing SAML metadata: " << e.what() << CategoryStream::ENDLINE;
1155 this->~XMLMetadataImpl();
1161 log.error("Unexpected error while parsing SAML metadata");
1162 this->~XMLMetadataImpl();
1167 if (!m_rootGroup && !m_rootProvider) {
1168 log.error("Metadata file contained no valid information");
1169 throw MetadataException("Metadata file contained no valid information");
1173 XMLMetadataImpl::~XMLMetadataImpl()
1176 delete m_rootProvider;
1179 XMLMetadata::XMLMetadata(const DOMElement* e) : ReloadableXMLFile(e), m_exclusions(true), m_verify(false), m_credResolver(NULL)
1181 static const XMLCh uri[] = { chLatin_u, chLatin_r, chLatin_i, chNull };
1182 if (e->hasAttributeNS(NULL,uri)) {
1183 // First check for explicit enablement of entities.
1184 DOMNodeList* nlist=e->getElementsByTagName(SHIB_L(Include));
1185 for (unsigned int i=0; nlist && i<nlist->getLength(); i++) {
1186 if (nlist->item(i)->hasChildNodes()) {
1187 auto_ptr_char temp(nlist->item(i)->getFirstChild()->getNodeValue());
1189 m_set.insert(temp.get());
1194 // If there was no explicit enablement, build a set of exclusions.
1196 nlist=e->getElementsByTagName(SHIB_L(Exclude));
1197 for (unsigned int j=0; nlist && j<nlist->getLength(); j++) {
1198 if (nlist->item(j)->hasChildNodes()) {
1199 auto_ptr_char temp(nlist->item(j)->getFirstChild()->getNodeValue());
1201 m_set.insert(temp.get());
1207 const XMLCh* v=e->getAttributeNS(NULL,SHIB_L(verify));
1208 m_verify=(v && (*v==chLatin_t || *v==chDigit_1));
1211 DOMElement* r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(FileResolver));
1213 cr_type="edu.internet2.middleware.shibboleth.common.Credentials.FileCredentialResolver";
1215 r=saml::XML::getFirstChildElement(e,::XML::CREDS_NS,SHIB_L(CustomResolver));
1217 auto_ptr_char c(r->getAttributeNS(NULL,SHIB_L(Class)));
1222 if (!cr_type.empty()) {
1224 IPlugIn* plugin=SAMLConfig::getConfig().getPlugMgr().newPlugin(cr_type.c_str(),r);
1225 ICredResolver* cr=dynamic_cast<ICredResolver*>(plugin);
1229 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("plugin was not a credential resolver");
1231 throw UnsupportedExtensionException("plugin was not a credential resolver");
1234 catch (SAMLException& e) {
1235 Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata").error("failed to instantiate credential resolver: %s", e.what());
1240 if (m_verify && !m_credResolver) {
1241 delete m_credResolver;
1242 throw MalformedException("Metadata provider told to verify signatures, but a verification key is not available.");
1246 bool XMLMetadata::verifySignature(DOMDocument* doc, const DOMElement* parent, bool failUnsigned) const
1252 saml::NDC ndc("verifySignature");
1254 Category& log=Category::getInstance(XMLPROVIDERS_LOGCAT".Metadata");
1256 DOMElement* sigNode=saml::XML::getFirstChildElement(parent,saml::XML::XMLSIG_NS,L(Signature));
1259 log.error("rejecting unsigned element");
1265 XSECCryptoX509* cert=NULL;
1266 Iterator<XSECCryptoX509*> certs=m_credResolver->getCertificates();
1267 if (certs.hasNext())
1270 log.error("unable to find any certificates to use in verifying signature");
1274 static const XMLCh ID[]={chLatin_I, chLatin_D, chNull};
1275 static const XMLCh null[]={chDoubleQuote, chDoubleQuote, chNull};
1277 // Load the signature.
1279 DSIGSignature* sig=NULL;
1281 sig=prov.newSignatureFromDOM(doc,sigNode);
1285 const XMLCh* URI=NULL;
1287 // Verify the signature coverage.
1288 DSIGReferenceList* refs=sig->getReferenceList();
1289 if (sig->getSignatureMethod()==SIGNATURE_RSA && refs && refs->getSize()==1) {
1290 DSIGReference* ref=refs->item(0);
1293 if (!URI || !*URI || (*URI==chPound &&
1294 !XMLString::compareString(&URI[1],static_cast<DOMElement*>(sigNode->getParentNode())->getAttributeNS(NULL,ID)))) {
1295 DSIGTransformList* tlist=ref->getTransforms();
1296 for (unsigned int i=0; tlist && i<tlist->getSize(); i++) {
1297 if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE)
1299 else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N &&
1300 tlist->item(i)->getTransformType()!=TRANSFORM_C14N) {
1310 auto_ptr_char temp((URI && *URI) ? URI : null);
1311 log.error("detected an invalid signature profile (Reference URI was %s)",temp.get());
1315 sig->setSigningKey(cert->clonePublicKey());
1316 if (!sig->verify()) {
1317 auto_ptr_char temp((URI && *URI) ? URI : null);
1318 log.error("detected an invalid signature value (Reference URI was %s)",temp.get());
1322 prov.releaseSignature(sig);
1324 catch(XSECException& e) {
1325 auto_ptr_char msg(e.getMsg());
1326 log.errorStream() << "caught XMLSec exception while verifying metadata signature: " << msg.get() << CategoryStream::ENDLINE;
1328 prov.releaseSignature(sig);
1331 catch(XSECCryptoException& e) {
1332 log.errorStream() << "caught XMLSecCrypto exception while verifying metadata signature: " << e.getMsg() << CategoryStream::ENDLINE;
1334 prov.releaseSignature(sig);
1339 prov.releaseSignature(sig);
1340 log.error("caught unknown exception while verifying metadata signature");
1346 const IEntityDescriptor* XMLMetadata::lookup(const char* providerId, bool strict) const
1348 if (strict && m_exclusions && m_set.find(providerId)!=m_set.end())
1350 else if (strict && !m_exclusions && m_set.find(providerId)==m_set.end())
1353 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1354 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range=
1355 impl->m_sites.equal_range(providerId);
1357 time_t now=time(NULL);
1358 for (XMLMetadataImpl::sitemap_t::const_iterator i=range.first; i!=range.second; i++)
1359 if (now < i->second->getValidUntil())
1362 if (!strict && range.first!=range.second)
1363 return range.first->second;
1368 const IEntityDescriptor* XMLMetadata::lookup(const XMLCh* providerId, bool strict) const
1370 auto_ptr_char temp(providerId);
1371 return lookup(temp.get(),strict);
1374 const IEntityDescriptor* XMLMetadata::lookup(const SAMLArtifact* artifact) const
1376 time_t now=time(NULL);
1377 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1378 pair<XMLMetadataImpl::sitemap_t::iterator,XMLMetadataImpl::sitemap_t::iterator> range;
1380 // Depends on type of artifact.
1381 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
1383 range=impl->m_sources.equal_range(SAMLArtifact::toHex(type1->getSourceID()));
1386 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
1388 range=impl->m_sources.equal_range(type2->getSourceLocation());
1394 // Check exclude list.
1395 if (range.first!=range.second) {
1396 auto_ptr_char id(range.first->second->getId());
1397 if (m_exclusions && m_set.find(id.get())!=m_set.end())
1399 else if (!m_exclusions && m_set.find(id.get())==m_set.end())
1402 for (XMLMetadataImpl::sitemap_t::iterator i=range.first; i!=range.second; i++)
1403 if (now < i->second->getValidUntil())
1410 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const char* name, bool strict) const
1412 if (strict && m_exclusions && m_set.find(name)!=m_set.end())
1414 else if (strict && !m_exclusions && m_set.find(name)==m_set.end())
1417 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1418 pair<XMLMetadataImpl::groupmap_t::iterator,XMLMetadataImpl::groupmap_t::iterator> range=
1419 impl->m_groups.equal_range(name);
1421 time_t now=time(NULL);
1422 for (XMLMetadataImpl::groupmap_t::iterator i=range.first; i!=range.second; i++)
1423 if (now < i->second->getValidUntil())
1426 if (!strict && range.first!=range.second)
1427 return range.first->second;
1432 const IEntitiesDescriptor* XMLMetadata::lookupGroup(const XMLCh* name, bool strict) const
1434 auto_ptr_char temp(name);
1435 return lookupGroup(temp.get(),strict);
1438 pair<const IEntitiesDescriptor*,const IEntityDescriptor*> XMLMetadata::getRoot() const
1440 XMLMetadataImpl* impl=dynamic_cast<XMLMetadataImpl*>(getImplementation());
1441 return pair<const IEntitiesDescriptor*,const IEntityDescriptor*>(impl->m_rootGroup,impl->m_rootProvider);