2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
22 * DiscoverableMetadataProvider.cpp
24 * A metadata provider that provides a JSON feed of IdP discovery information.
28 #include "binding/SAMLArtifact.h"
29 #include "saml2/metadata/Metadata.h"
30 #include "saml2/metadata/DiscoverableMetadataProvider.h"
34 #include <boost/bind.hpp>
35 #include <boost/iterator/indirect_iterator.hpp>
36 #include <xmltooling/logging.h>
37 #include <xmltooling/XMLToolingConfig.h>
39 using namespace opensaml::saml2md;
40 using namespace xmltooling;
41 using namespace boost;
44 DiscoverableMetadataProvider::DiscoverableMetadataProvider(const DOMElement* e) : MetadataProvider(e), m_legacyOrgNames(false)
46 static const XMLCh legacyOrgNames[] = UNICODE_LITERAL_14(l,e,g,a,c,y,O,r,g,N,a,m,e,s);
47 m_legacyOrgNames = XMLHelper::getAttrBool(e, false, legacyOrgNames);
50 DiscoverableMetadataProvider::~DiscoverableMetadataProvider()
54 void DiscoverableMetadataProvider::generateFeed()
58 const XMLObject* object = getMetadata();
59 discoGroup(m_feed, dynamic_cast<const EntitiesDescriptor*>(object), first);
60 discoEntity(m_feed, dynamic_cast<const EntityDescriptor*>(object), first);
62 SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4);
63 m_feedTag = SAMLArtifact::toHex(m_feedTag);
66 string DiscoverableMetadataProvider::getCacheTag() const
71 void DiscoverableMetadataProvider::outputFeed(ostream& os, bool& first, bool wrapArray) const
75 if (!m_feed.empty()) {
86 static string& json_safe(string& s, const char* buf)
117 void DiscoverableMetadataProvider::discoEntity(string& s, const EntityDescriptor* entity, bool& first) const
119 time_t now = time(nullptr);
120 if (entity && entity->isValid(now)) {
121 const vector<IDPSSODescriptor*>& idps = entity->getIDPSSODescriptors();
123 auto_ptr_char entityid(entity->getEntityID());
124 // Open a struct and output id: entityID.
129 s += "\n{\n \"entityID\": \"";
130 json_safe(s, entityid.get());
132 bool extFound = false;
133 for (indirect_iterator<vector<IDPSSODescriptor*>::const_iterator> idp = make_indirect_iterator(idps.begin());
134 !extFound && idp != make_indirect_iterator(idps.end()); ++idp) {
135 if (idp->isValid(now) && idp->getExtensions()) {
136 const vector<XMLObject*>& exts = const_cast<const Extensions*>(idp->getExtensions())->getUnknownXMLObjects();
137 for (vector<XMLObject*>::const_iterator ext = exts.begin(); !extFound && ext != exts.end(); ++ext) {
138 const UIInfo* info = dynamic_cast<UIInfo*>(*ext);
141 const vector<DisplayName*>& dispnames = info->getDisplayNames();
142 if (!dispnames.empty()) {
143 s += ",\n \"DisplayNames\": [";
144 for (indirect_iterator<vector<DisplayName*>::const_iterator> dispname = make_indirect_iterator(dispnames.begin());
145 dispname != make_indirect_iterator(dispnames.end()); ++dispname) {
146 if (dispname.base() != dispnames.begin())
148 auto_arrayptr<char> val(toUTF8(dispname->getName()));
149 auto_ptr_char lang(dispname->getLang());
150 s += "\n {\n \"value\": \"";
151 json_safe(s, val.get());
152 s += "\",\n \"lang\": \"";
159 const vector<Description*>& descs = info->getDescriptions();
160 if (!descs.empty()) {
161 s += ",\n \"Descriptions\": [";
162 for (indirect_iterator<vector<Description*>::const_iterator> desc = make_indirect_iterator(descs.begin());
163 desc != make_indirect_iterator(descs.end()); ++desc) {
164 if (desc.base() != descs.begin())
166 auto_arrayptr<char> val(toUTF8(desc->getDescription()));
167 auto_ptr_char lang(desc->getLang());
168 s += "\n {\n \"value\": \"";
169 json_safe(s, val.get());
170 s += "\",\n \"lang\": \"";
177 const vector<Keywords*>& keywords = info->getKeywordss();
178 if (!keywords.empty()) {
179 s += ",\n \"Keywords\": [";
180 for (indirect_iterator<vector<Keywords*>::const_iterator> words = make_indirect_iterator(keywords.begin());
181 words != make_indirect_iterator(keywords.end()); ++words) {
182 if (words.base() != keywords.begin())
184 auto_arrayptr<char> val(toUTF8(words->getValues()));
185 auto_ptr_char lang(words->getLang());
186 s += "\n {\n \"value\": \"";
187 json_safe(s, val.get());
188 s += "\",\n \"lang\": \"";
195 const vector<InformationURL*>& infurls = info->getInformationURLs();
196 if (!infurls.empty()) {
197 s += ",\n \"InformationURLs\": [";
198 for (indirect_iterator<vector<InformationURL*>::const_iterator> infurl = make_indirect_iterator(infurls.begin());
199 infurl != make_indirect_iterator(infurls.end()); ++infurl) {
200 if (infurl.base() != infurls.begin())
202 auto_ptr_char val(infurl->getURL());
203 auto_ptr_char lang(infurl->getLang());
204 s += "\n {\n \"value\": \"";
205 json_safe(s, val.get());
206 s += "\",\n \"lang\": \"";
213 const vector<PrivacyStatementURL*>& privs = info->getPrivacyStatementURLs();
214 if (!privs.empty()) {
215 s += ",\n \"PrivacyStatementURLs\": [";
216 for (indirect_iterator<vector<PrivacyStatementURL*>::const_iterator> priv = make_indirect_iterator(privs.begin());
217 priv != make_indirect_iterator(privs.end()); ++priv) {
218 if (priv.base() != privs.begin())
220 auto_ptr_char val(priv->getURL());
221 auto_ptr_char lang(priv->getLang());
222 s += "\n {\n \"value\": \"";
223 json_safe(s, val.get());
224 s += "\",\n \"lang\": \"";
231 const vector<Logo*>& logos = info->getLogos();
232 if (!logos.empty()) {
233 s += ",\n \"Logos\": [";
234 for (indirect_iterator<vector<Logo*>::const_iterator> logo = make_indirect_iterator(logos.begin());
235 logo != make_indirect_iterator(logos.end()); ++logo) {
236 if (logo.base() != logos.begin())
239 auto_ptr_char val(logo->getURL());
240 s += " \"value\": \"";
241 json_safe(s, val.get());
243 ht << logo->getHeight().second;
244 s += "\",\n \"height\": \"";
247 wt << logo->getWidth().second;
248 s += "\",\n \"width\": \"";
251 if (logo->getLang()) {
252 auto_ptr_char lang(logo->getLang());
253 s += ",\n \"lang\": \"";
266 if (m_legacyOrgNames && !extFound) {
267 const Organization* org = nullptr;
268 for (indirect_iterator<vector<IDPSSODescriptor*>::const_iterator> idp = make_indirect_iterator(idps.begin());
269 !org && idp != make_indirect_iterator(idps.end()); ++idp) {
270 if (idp->isValid(now))
271 org = idp->getOrganization();
274 org = entity->getOrganization();
276 const vector<OrganizationDisplayName*>& odns = org->getOrganizationDisplayNames();
278 s += ",\n \"DisplayNames\": [";
279 for (indirect_iterator<vector<OrganizationDisplayName*>::const_iterator> dispname = make_indirect_iterator(odns.begin());
280 dispname != make_indirect_iterator(odns.end()); ++dispname) {
281 if (dispname.base() != odns.begin())
283 auto_arrayptr<char> val(toUTF8(dispname->getName()));
284 auto_ptr_char lang(dispname->getLang());
285 s += "\n {\n \"value\": \"";
286 json_safe(s, val.get());
287 s += "\",\n \"lang\": \"";
302 void DiscoverableMetadataProvider::discoGroup(string& s, const EntitiesDescriptor* group, bool& first) const
306 group->getEntitiesDescriptors().begin(), group->getEntitiesDescriptors().end(),
307 boost::bind(&DiscoverableMetadataProvider::discoGroup, this, boost::ref(s), _1, boost::ref(first))
310 group->getEntityDescriptors().begin(), group->getEntityDescriptors().end(),
311 boost::bind(&DiscoverableMetadataProvider::discoEntity, this, boost::ref(s), _1, boost::ref(first))