From: Scott Cantor Date: Sat, 18 Sep 2010 02:54:22 +0000 (+0000) Subject: https://issues.shibboleth.net/jira/browse/SSPCPP-254 X-Git-Tag: 2.4RC1~27 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=c3f264f74b05ef3541684b85002bc876b9faa1e1 https://issues.shibboleth.net/jira/browse/SSPCPP-254 --- diff --git a/saml/Makefile.am b/saml/Makefile.am index addb22d..a0dd1dd 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -84,6 +84,7 @@ saml2bindinclude_HEADERS = \ saml2mdinclude_HEADERS = \ saml2/metadata/AbstractMetadataProvider.h \ + saml2/metadata/DiscoverableMetadataProvider.h \ saml2/metadata/DynamicMetadataProvider.h \ saml2/metadata/EndpointManager.h \ saml2/metadata/Metadata.h \ @@ -142,6 +143,7 @@ libsaml_la_SOURCES = \ saml2/metadata/impl/AbstractMetadataProvider.cpp \ saml2/metadata/impl/BlacklistMetadataFilter.cpp \ saml2/metadata/impl/ChainingMetadataProvider.cpp \ + saml2/metadata/impl/DiscoverableMetadataProvider.cpp \ saml2/metadata/impl/DynamicMetadataProvider.cpp \ saml2/metadata/impl/EntityRoleMetadataFilter.cpp \ saml2/metadata/impl/MetadataCredentialContext.cpp \ diff --git a/saml/saml.rc b/saml/saml.rc index b32b3f2..559837d 100644 --- a/saml/saml.rc +++ b/saml/saml.rc @@ -53,7 +53,7 @@ BEGIN #else VALUE "InternalName", "saml2_4\0" #endif - VALUE "LegalCopyright", "Copyright © 2009 Internet2\0" + VALUE "LegalCopyright", "Copyright © 2010 Internet2\0" VALUE "LegalTrademarks", "\0" #ifdef _DEBUG VALUE "OriginalFilename", "saml2_4D.dll\0" diff --git a/saml/saml.vcxproj b/saml/saml.vcxproj index 2c3416b..c817340 100644 --- a/saml/saml.vcxproj +++ b/saml/saml.vcxproj @@ -178,6 +178,7 @@ + @@ -281,6 +282,7 @@ + diff --git a/saml/saml.vcxproj.filters b/saml/saml.vcxproj.filters index 9c9d9bc..7bef27d 100644 --- a/saml/saml.vcxproj.filters +++ b/saml/saml.vcxproj.filters @@ -357,6 +357,9 @@ Source Files\profile\impl + + Source Files\saml2\metadata\impl + @@ -500,6 +503,9 @@ Header Files\binding + + Header Files\saml2\metadata + diff --git a/saml/saml2/metadata/DiscoverableMetadataProvider.h b/saml/saml2/metadata/DiscoverableMetadataProvider.h new file mode 100644 index 0000000..a9bdb5a --- /dev/null +++ b/saml/saml2/metadata/DiscoverableMetadataProvider.h @@ -0,0 +1,85 @@ +/* + * Copyright 2010 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file saml/saml2/metadata/DiscoverableMetadataProvider.h + * + * A metadata provider that provides a JSON feed of IdP discovery information. + */ + +#ifndef __saml2_discometadataprov_h__ +#define __saml2_discometadataprov_h__ + +#include + +namespace opensaml { + + namespace saml2md { + +#if defined (_MSC_VER) + #pragma warning( push ) + #pragma warning( disable : 4251 ) +#endif + /** + * A metadata provider that provides a JSON feed of IdP discovery information. + */ + class SAML_API DiscoverableMetadataProvider : public virtual MetadataProvider + { + protected: + DiscoverableMetadataProvider(); + + /** + * Generates a JSON feed of IdP discovery information for the current metadata. + *

The provider MUST be write-locked. + */ + virtual void generateFeed(); + + public: + virtual ~DiscoverableMetadataProvider(); + + /** + * Returns the ETag associated with the cached feed. + *

The provider MUST be locked. + * + * @return the ETag value for the current feed state + */ + virtual std::string getCacheTag() const; + + /** + * Outputs the cached feed. + *

The provider MUST be locked. + * + * @param os stream to output feed into + * @return a reference to the output stream + */ + virtual std::ostream& outputFeed(std::ostream& os) const; + + protected: + /** Storage for feed. */ + std::string m_feed; + + /** ETag for feed. */ + mutable std::string m_feedTag; + }; + +#if defined (_MSC_VER) + #pragma warning( pop ) +#endif + + }; +}; + +#endif /* __saml2_discometadataprov_h__ */ diff --git a/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp index 617c8e6..3e5f312 100644 --- a/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/ChainingMetadataProvider.cpp @@ -24,6 +24,7 @@ #include "exceptions.h" #include "saml/binding/SAMLArtifact.h" #include "saml2/metadata/Metadata.h" +#include "saml2/metadata/DiscoverableMetadataProvider.h" #include "saml2/metadata/ObservableMetadataProvider.h" #include "saml2/metadata/MetadataCredentialCriteria.h" @@ -48,7 +49,7 @@ namespace opensaml { struct SAML_DLLLOCAL tracker_t; class SAML_DLLLOCAL ChainingMetadataProvider - : public ObservableMetadataProvider, public ObservableMetadataProvider::Observer { + : public DiscoverableMetadataProvider, public ObservableMetadataProvider, public ObservableMetadataProvider::Observer { public: ChainingMetadataProvider(const xercesc::DOMElement* e=nullptr); virtual ~ChainingMetadataProvider(); @@ -62,11 +63,42 @@ namespace opensaml { const XMLObject* getMetadata() const; const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const; pair getEntityDescriptor(const Criteria& criteria) const; - void onEvent(const ObservableMetadataProvider& provider) const; const Credential* resolve(const CredentialCriteria* criteria=nullptr) const; vector::size_type resolve(vector& results, const CredentialCriteria* criteria=nullptr) const; + string getCacheTag() const { + Lock lock(m_trackerLock); + return m_feedTag; + } + + ostream& outputFeed(ostream& os) const { + os << "[\n"; + // Lock each provider in turn and suck in its feed. + for (vector::const_iterator m = m_providers.begin(); m != m_providers.end(); ++m) { + DiscoverableMetadataProvider* d = dynamic_cast(*m); + if (d) { + Locker locker(d); + d->outputFeed(os); + } + } + os << "]\n"; + return os; + } + + void onEvent(const ObservableMetadataProvider& provider) const { + // Reset the cache tag for the feed. + Lock lock(m_trackerLock); + SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4); + m_feedTag = SAMLArtifact::toHex(m_feedTag); + emitChangeEvent(); + } + + protected: + void generateFeed() { + // No-op. + } + private: bool m_firstMatch; mutable Mutex* m_trackerLock; @@ -171,11 +203,6 @@ ChainingMetadataProvider::~ChainingMetadataProvider() for_each(m_providers.begin(), m_providers.end(), xmltooling::cleanup()); } -void ChainingMetadataProvider::onEvent(const ObservableMetadataProvider& provider) const -{ - emitChangeEvent(); -} - void ChainingMetadataProvider::init() { for (vector::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) { @@ -186,6 +213,10 @@ void ChainingMetadataProvider::init() m_log.crit("failure initializing MetadataProvider: %s", ex.what()); } } + + // Set an initial cache tag for the state of the plugins. + SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4); + m_feedTag = SAMLArtifact::toHex(m_feedTag); } Lockable* ChainingMetadataProvider::lock() diff --git a/saml/saml2/metadata/impl/DiscoverableMetadataProvider.cpp b/saml/saml2/metadata/impl/DiscoverableMetadataProvider.cpp new file mode 100644 index 0000000..eaec6cc --- /dev/null +++ b/saml/saml2/metadata/impl/DiscoverableMetadataProvider.cpp @@ -0,0 +1,196 @@ +/* + * Copyright 2010 Internet2 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * DiscoverableMetadataProvider.cpp + * + * A metadata provider that provides a JSON feed of IdP discovery information. + */ + +#include "internal.h" +#include "binding/SAMLArtifact.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/DiscoverableMetadataProvider.h" + +#include +#include +#include + +using namespace opensaml::saml2md; +using namespace xmltooling; +using namespace std; + +namespace { + void disco(string& s, const EntityDescriptor* entity) { + if (entity) { + const vector& idps = entity->getIDPSSODescriptors(); + if (!idps.empty()) { + auto_ptr_char entityid(entity->getEntityID()); + // Open a struct and output id: entityID. + s += "{\n \"id\": \""; + s += entityid.get(); + s += '\"'; + for (vector::const_iterator idp = idps.begin(); idp != idps.end(); ++idp) { + if ((*idp)->getExtensions()) { + const vector& exts = const_cast((*idp)->getExtensions())->getUnknownXMLObjects(); + for (vector::const_iterator ext = exts.begin(); ext != exts.end(); ++ext) { + const UIInfo* info = dynamic_cast(*ext); + if (info) { + const vector& dispnames = info->getDisplayNames(); + if (!dispnames.empty()) { + s += ",\n \"names\": ["; + for (vector::const_iterator dispname = dispnames.begin(); dispname != dispnames.end(); ++dispname) { + if (dispname != dispnames.begin()) + s += ','; + auto_ptr_char dn((*dispname)->getName()); + auto_ptr_char lang((*dispname)->getLang()); + s += "\n {\n \"name\": \""; + s += dn.get(); + s += "\",\n \"lang\": \""; + s += lang.get(); + s += "\"\n }"; + } + s += "\n ]"; + } + + const vector& descs = info->getDescriptions(); + if (!descs.empty()) { + s += ",\n \"descs\": ["; + for (vector::const_iterator desc = descs.begin(); desc != descs.end(); ++desc) { + if (desc != descs.begin()) + s += ','; + auto_ptr_char d((*desc)->getDescription()); + auto_ptr_char lang((*desc)->getLang()); + s += "\n {\n \"desc\": \""; + s += d.get(); + s += "\",\n \"lang\": \""; + s += lang.get(); + s += "\"\n }"; + } + s += "\n ]"; + } + + const vector& infurls = info->getInformationURLs(); + if (!infurls.empty()) { + s += ",\n \"infolinks\": ["; + for (vector::const_iterator infurl = infurls.begin(); infurl != infurls.end(); ++infurl) { + if (infurl != infurls.begin()) + s += ','; + auto_ptr_char iu((*infurl)->getURL()); + auto_ptr_char lang((*infurl)->getLang()); + s += "\n {\n \"url\": \""; + s += iu.get(); + s += "\",\n \"lang\": \""; + s += lang.get(); + s += "\"\n }"; + } + s += "\n ]"; + } + + const vector& privs = info->getPrivacyStatementURLs(); + if (!privs.empty()) { + s += ",\n \"privlinks\": ["; + for (vector::const_iterator priv = privs.begin(); priv != privs.end(); ++priv) { + if (priv != privs.begin()) + s += ','; + auto_ptr_char pu((*priv)->getURL()); + auto_ptr_char lang((*priv)->getLang()); + s += "\n {\n \"url\": \""; + s += pu.get(); + s += "\",\n \"lang\": \""; + s += lang.get(); + s += "\"\n }"; + } + s += "\n ]"; + } + + const vector& logos = info->getLogos(); + if (!logos.empty()) { + s += ",\n \"logos\": ["; + for (vector::const_iterator logo = logos.begin(); logo != logos.end(); ++logo) { + if (logo != logos.begin()) + s += ','; + s += "\n {\n"; + auto_ptr_char imgsrc((*logo)->getURL()); + s += " \"imgsrc\": \""; + s += imgsrc.get(); + s += "\",\n \"height\": \""; + s += (*logo)->getHeight().second; + s += "\",\n \"width\": \""; + s += (*logo)->getWidth().second; + s += '\"'; + if ((*logo)->getLang()) { + auto_ptr_char lang((*logo)->getLang()); + s += ",\n \"lang\": \""; + s += lang.get(); + s += '\"'; + } + s += "\n }"; + } + s += "\n ]"; + } + } + } + } + } + // Close the struct; + s += "\n},\n"; + } + } + } + + void disco(string& s, const EntitiesDescriptor* group) { + if (group) { + const vector& groups = group->getEntitiesDescriptors(); + for (vector::const_iterator i = groups.begin(); i != groups.end(); ++i) + disco(s, *i); + + const vector& sites = group->getEntityDescriptors(); + for (vector::const_iterator j = sites.begin(); j != sites.end(); ++j) + disco(s, *j); + } + } +} + +DiscoverableMetadataProvider::DiscoverableMetadataProvider() +{ +} + +DiscoverableMetadataProvider::~DiscoverableMetadataProvider() +{ +} + +void DiscoverableMetadataProvider::generateFeed() +{ + m_feed = "[\n"; + const XMLObject* object = getMetadata(); + disco(m_feed, dynamic_cast(object)); + disco(m_feed, dynamic_cast(object)); + m_feed += " { }\n]\n"; + + SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4); + m_feedTag = SAMLArtifact::toHex(m_feedTag); +} + +string DiscoverableMetadataProvider::getCacheTag() const +{ + return m_feedTag; +} + +ostream& DiscoverableMetadataProvider::outputFeed(ostream& os) const +{ + return os << m_feed; +} diff --git a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp b/saml/saml2/metadata/impl/XMLMetadataProvider.cpp index df85913..3d88264 100644 --- a/saml/saml2/metadata/impl/XMLMetadataProvider.cpp +++ b/saml/saml2/metadata/impl/XMLMetadataProvider.cpp @@ -25,10 +25,13 @@ #include "saml2/metadata/Metadata.h" #include "saml2/metadata/MetadataFilter.h" #include "saml2/metadata/AbstractMetadataProvider.h" +#include "saml2/metadata/DiscoverableMetadataProvider.h" #include +#include #include #include +#include #include #include #include @@ -46,7 +49,8 @@ using namespace std; namespace opensaml { namespace saml2md { - class SAML_DLLLOCAL XMLMetadataProvider : public AbstractMetadataProvider, public ReloadableXMLFile + class SAML_DLLLOCAL XMLMetadataProvider + : public AbstractMetadataProvider, public DiscoverableMetadataProvider, public ReloadableXMLFile { public: XMLMetadataProvider(const DOMElement* e); @@ -81,6 +85,7 @@ namespace opensaml { time_t computeNextRefresh(); XMLObject* m_object; + bool m_discoveryFeed; double m_refreshDelayFactor; unsigned int m_backoffFactor; time_t m_minRefreshDelay,m_maxRefreshDelay,m_lastValidUntil; @@ -91,6 +96,7 @@ namespace opensaml { return new XMLMetadataProvider(e); } + static const XMLCh discoveryFeed[] = UNICODE_LITERAL_13(d,i,s,c,o,v,e,r,y,F,e,e,d); static const XMLCh minRefreshDelay[] = UNICODE_LITERAL_15(m,i,n,R,e,f,r,e,s,h,D,e,l,a,y); static const XMLCh refreshDelayFactor[] = UNICODE_LITERAL_18(r,e,f,r,e,s,h,D,e,l,a,y,F,a,c,t,o,r); }; @@ -102,7 +108,8 @@ namespace opensaml { XMLMetadataProvider::XMLMetadataProvider(const DOMElement* e) : AbstractMetadataProvider(e), ReloadableXMLFile(e, Category::getInstance(SAML_LOGCAT".MetadataProvider.XML"), false), - m_object(nullptr), m_refreshDelayFactor(0.75), m_backoffFactor(1), + m_object(nullptr), m_discoveryFeed(XMLHelper::getAttrBool(e, true, discoveryFeed)), + m_refreshDelayFactor(0.75), m_backoffFactor(1), m_minRefreshDelay(XMLHelper::getAttrInt(e, 600, minRefreshDelay)), m_maxRefreshDelay(m_reloadInterval), m_lastValidUntil(SAMLTIME_MAX) { @@ -200,6 +207,8 @@ pair XMLMetadataProvider::load(bool backup) m_object = xmlObject.release(); m_lastValidUntil = SAMLTIME_MAX; index(m_lastValidUntil); + if (m_discoveryFeed) + generateFeed(); if (changed) emitChangeEvent(); @@ -252,17 +261,6 @@ pair XMLMetadataProvider::background_load() } } -void XMLMetadataProvider::index(time_t& validUntil) -{ - clearDescriptorIndex(); - EntitiesDescriptor* group=dynamic_cast(m_object); - if (group) { - indexGroup(group, validUntil); - return; - } - indexEntity(dynamic_cast(m_object), validUntil); -} - time_t XMLMetadataProvider::computeNextRefresh() { time_t now = time(nullptr); @@ -290,3 +288,14 @@ time_t XMLMetadataProvider::computeNextRefresh() return ret; } } + +void XMLMetadataProvider::index(time_t& validUntil) +{ + clearDescriptorIndex(); + EntitiesDescriptor* group=dynamic_cast(m_object); + if (group) { + indexGroup(group, validUntil); + return; + } + indexEntity(dynamic_cast(m_object), validUntil); +}