saml2mdinclude_HEADERS = \
saml2/metadata/AbstractMetadataProvider.h \
+ saml2/metadata/DiscoverableMetadataProvider.h \
saml2/metadata/DynamicMetadataProvider.h \
saml2/metadata/EndpointManager.h \
saml2/metadata/Metadata.h \
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 \
#else\r
VALUE "InternalName", "saml2_4\0"\r
#endif\r
- VALUE "LegalCopyright", "Copyright © 2009 Internet2\0"\r
+ VALUE "LegalCopyright", "Copyright © 2010 Internet2\0"\r
VALUE "LegalTrademarks", "\0"\r
#ifdef _DEBUG\r
VALUE "OriginalFilename", "saml2_4D.dll\0"\r
</Link>\r
</ItemDefinitionGroup>\r
<ItemGroup>\r
+ <ClCompile Include="saml2\metadata\impl\DiscoverableMetadataProvider.cpp" />\r
<ClCompile Include="SAMLConfig.cpp" />\r
<ClCompile Include="util\CommonDomainCookie.cpp" />\r
<ClCompile Include="util\SAMLConstants.cpp" />\r
<ClInclude Include="exceptions.h" />\r
<ClInclude Include="internal.h" />\r
<ClInclude Include="RootObject.h" />\r
+ <ClInclude Include="saml2\metadata\DiscoverableMetadataProvider.h" />\r
<ClInclude Include="SAMLConfig.h" />\r
<ClInclude Include="version.h" />\r
<ClInclude Include="util\CommonDomainCookie.h" />\r
<ClCompile Include="profile\impl\IgnoreRule.cpp">\r
<Filter>Source Files\profile\impl</Filter>\r
</ClCompile>\r
+ <ClCompile Include="saml2\metadata\impl\DiscoverableMetadataProvider.cpp">\r
+ <Filter>Source Files\saml2\metadata\impl</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="Assertion.h">\r
<ClInclude Include="binding\SOAPClient.h">\r
<Filter>Header Files\binding</Filter>\r
</ClInclude>\r
+ <ClInclude Include="saml2\metadata\DiscoverableMetadataProvider.h">\r
+ <Filter>Header Files\saml2\metadata</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<ResourceCompile Include="saml.rc">\r
--- /dev/null
+/*
+ * 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 <saml/saml2/metadata/MetadataProvider.h>
+
+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.
+ * <p>The provider <strong>MUST</strong> be write-locked.
+ */
+ virtual void generateFeed();
+
+ public:
+ virtual ~DiscoverableMetadataProvider();
+
+ /**
+ * Returns the ETag associated with the cached feed.
+ * <p>The provider <strong>MUST</strong> be locked.
+ *
+ * @return the ETag value for the current feed state
+ */
+ virtual std::string getCacheTag() const;
+
+ /**
+ * Outputs the cached feed.
+ * <p>The provider <strong>MUST</strong> 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__ */
#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"
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();
const XMLObject* getMetadata() const;
const EntitiesDescriptor* getEntitiesDescriptor(const char* name, bool requireValidMetadata=true) const;
pair<const EntityDescriptor*,const RoleDescriptor*> getEntityDescriptor(const Criteria& criteria) const;
- void onEvent(const ObservableMetadataProvider& provider) const;
const Credential* resolve(const CredentialCriteria* criteria=nullptr) const;
vector<const Credential*>::size_type resolve(vector<const Credential*>& 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<MetadataProvider*>::const_iterator m = m_providers.begin(); m != m_providers.end(); ++m) {
+ DiscoverableMetadataProvider* d = dynamic_cast<DiscoverableMetadataProvider*>(*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;
for_each(m_providers.begin(), m_providers.end(), xmltooling::cleanup<MetadataProvider>());
}
-void ChainingMetadataProvider::onEvent(const ObservableMetadataProvider& provider) const
-{
- emitChangeEvent();
-}
-
void ChainingMetadataProvider::init()
{
for (vector<MetadataProvider*>::const_iterator i=m_providers.begin(); i!=m_providers.end(); ++i) {
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()
--- /dev/null
+/*
+ * 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 <fstream>
+#include <xmltooling/logging.h>
+#include <xmltooling/XMLToolingConfig.h>
+
+using namespace opensaml::saml2md;
+using namespace xmltooling;
+using namespace std;
+
+namespace {
+ void disco(string& s, const EntityDescriptor* entity) {
+ if (entity) {
+ const vector<IDPSSODescriptor*>& 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<IDPSSODescriptor*>::const_iterator idp = idps.begin(); idp != idps.end(); ++idp) {
+ if ((*idp)->getExtensions()) {
+ const vector<XMLObject*>& exts = const_cast<const Extensions*>((*idp)->getExtensions())->getUnknownXMLObjects();
+ for (vector<XMLObject*>::const_iterator ext = exts.begin(); ext != exts.end(); ++ext) {
+ const UIInfo* info = dynamic_cast<UIInfo*>(*ext);
+ if (info) {
+ const vector<DisplayName*>& dispnames = info->getDisplayNames();
+ if (!dispnames.empty()) {
+ s += ",\n \"names\": [";
+ for (vector<DisplayName*>::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<Description*>& descs = info->getDescriptions();
+ if (!descs.empty()) {
+ s += ",\n \"descs\": [";
+ for (vector<Description*>::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<InformationURL*>& infurls = info->getInformationURLs();
+ if (!infurls.empty()) {
+ s += ",\n \"infolinks\": [";
+ for (vector<InformationURL*>::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<PrivacyStatementURL*>& privs = info->getPrivacyStatementURLs();
+ if (!privs.empty()) {
+ s += ",\n \"privlinks\": [";
+ for (vector<PrivacyStatementURL*>::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<Logo*>& logos = info->getLogos();
+ if (!logos.empty()) {
+ s += ",\n \"logos\": [";
+ for (vector<Logo*>::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<EntitiesDescriptor*>& groups = group->getEntitiesDescriptors();
+ for (vector<EntitiesDescriptor*>::const_iterator i = groups.begin(); i != groups.end(); ++i)
+ disco(s, *i);
+
+ const vector<EntityDescriptor*>& sites = group->getEntityDescriptors();
+ for (vector<EntityDescriptor*>::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<const EntitiesDescriptor*>(object));
+ disco(m_feed, dynamic_cast<const EntityDescriptor*>(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;
+}
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataFilter.h"
#include "saml2/metadata/AbstractMetadataProvider.h"
+#include "saml2/metadata/DiscoverableMetadataProvider.h"
#include <fstream>
+#include <xmltooling/XMLToolingConfig.h>
#include <xmltooling/io/HTTPResponse.h>
#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/PathResolver.h>
#include <xmltooling/util/ReloadableXMLFile.h>
#include <xmltooling/util/Threads.h>
#include <xmltooling/validation/ValidatorSuite.h>
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);
time_t computeNextRefresh();
XMLObject* m_object;
+ bool m_discoveryFeed;
double m_refreshDelayFactor;
unsigned int m_backoffFactor;
time_t m_minRefreshDelay,m_maxRefreshDelay,m_lastValidUntil;
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);
};
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)
{
m_object = xmlObject.release();
m_lastValidUntil = SAMLTIME_MAX;
index(m_lastValidUntil);
+ if (m_discoveryFeed)
+ generateFeed();
if (changed)
emitChangeEvent();
}
}
-void XMLMetadataProvider::index(time_t& validUntil)
-{
- clearDescriptorIndex();
- EntitiesDescriptor* group=dynamic_cast<EntitiesDescriptor*>(m_object);
- if (group) {
- indexGroup(group, validUntil);
- return;
- }
- indexEntity(dynamic_cast<EntityDescriptor*>(m_object), validUntil);
-}
-
time_t XMLMetadataProvider::computeNextRefresh()
{
time_t now = time(nullptr);
return ret;
}
}
+
+void XMLMetadataProvider::index(time_t& validUntil)
+{
+ clearDescriptorIndex();
+ EntitiesDescriptor* group=dynamic_cast<EntitiesDescriptor*>(m_object);
+ if (group) {
+ indexGroup(group, validUntil);
+ return;
+ }
+ indexEntity(dynamic_cast<EntityDescriptor*>(m_object), validUntil);
+}