634caf60c8f58c908b1c8b856b95a33a502bf10c
[shibboleth/cpp-opensaml.git] / saml / saml2 / metadata / impl / DiscoverableMetadataProvider.cpp
1 /*
2  *  Copyright 2010 Internet2
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * DiscoverableMetadataProvider.cpp
19  *
20  * A metadata provider that provides a JSON feed of IdP discovery information.
21  */
22
23 #include "internal.h"
24 #include "binding/SAMLArtifact.h"
25 #include "saml2/metadata/Metadata.h"
26 #include "saml2/metadata/DiscoverableMetadataProvider.h"
27
28 #include <fstream>
29 #include <sstream>
30 #include <xmltooling/logging.h>
31 #include <xmltooling/XMLToolingConfig.h>
32
33 using namespace opensaml::saml2md;
34 using namespace xmltooling;
35 using namespace std;
36
37 DiscoverableMetadataProvider::DiscoverableMetadataProvider(const DOMElement* e) : m_legacyOrgNames(false)
38 {
39     static const XMLCh legacyOrgNames[] = UNICODE_LITERAL_14(l,e,g,a,c,y,O,r,g,N,a,m,e,s);
40     m_legacyOrgNames = XMLHelper::getAttrBool(e, false, legacyOrgNames);
41 }
42
43 DiscoverableMetadataProvider::~DiscoverableMetadataProvider()
44 {
45 }
46
47 void DiscoverableMetadataProvider::generateFeed()
48 {
49     bool first = true;
50     m_feed = "[";
51     const XMLObject* object = getMetadata();
52     disco(m_feed, dynamic_cast<const EntitiesDescriptor*>(object), first);
53     disco(m_feed, dynamic_cast<const EntityDescriptor*>(object), first);
54     m_feed += "\n]";
55
56     SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4);
57     m_feedTag = SAMLArtifact::toHex(m_feedTag);
58 }
59
60 string DiscoverableMetadataProvider::getCacheTag() const
61 {
62     return m_feedTag;
63 }
64
65 ostream& DiscoverableMetadataProvider::outputFeed(ostream& os) const
66 {
67     return os << m_feed;
68 }
69
70 void DiscoverableMetadataProvider::disco(string& s, const EntityDescriptor* entity, bool& first) const
71 {
72     time_t now = time(nullptr);
73     if (entity && entity->isValid(now)) {
74         const vector<IDPSSODescriptor*>& idps = entity->getIDPSSODescriptors();
75         if (!idps.empty()) {
76             auto_ptr_char entityid(entity->getEntityID());
77             // Open a struct and output id: entityID.
78             if (first)
79                 first = false;
80             else
81                 s += ',';
82             s += "\n{\n \"entityID\": \"";
83             s += entityid.get();
84             s += '\"';
85             bool extFound = false;
86             for (vector<IDPSSODescriptor*>::const_iterator idp = idps.begin(); !extFound && idp != idps.end(); ++idp) {
87                 if ((*idp)->isValid(now) && (*idp)->getExtensions()) {
88                     const vector<XMLObject*>& exts =  const_cast<const Extensions*>((*idp)->getExtensions())->getUnknownXMLObjects();
89                     for (vector<XMLObject*>::const_iterator ext = exts.begin(); !extFound && ext != exts.end(); ++ext) {
90                         const UIInfo* info = dynamic_cast<UIInfo*>(*ext);
91                         if (info) {
92                             extFound = true;
93                             const vector<DisplayName*>& dispnames = info->getDisplayNames();
94                             if (!dispnames.empty()) {
95                                 s += ",\n \"DisplayNames\": [";
96                                 for (vector<DisplayName*>::const_iterator dispname = dispnames.begin(); dispname != dispnames.end(); ++dispname) {
97                                     if (dispname != dispnames.begin())
98                                         s += ',';
99                                     auto_arrayptr<char> val(toUTF8((*dispname)->getName()));
100                                     auto_ptr_char lang((*dispname)->getLang());
101                                     s += "\n  {\n  \"value\": \"";
102                                     s += val.get();
103                                     s += "\",\n  \"lang\": \"";
104                                     s += lang.get();
105                                     s += "\"\n  }";
106                                 }
107                                 s += "\n ]";
108                             }
109
110                             const vector<Description*>& descs = info->getDescriptions();
111                             if (!descs.empty()) {
112                                 s += ",\n \"Descriptions\": [";
113                                 for (vector<Description*>::const_iterator desc = descs.begin(); desc != descs.end(); ++desc) {
114                                     if (desc != descs.begin())
115                                         s += ',';
116                                     auto_arrayptr<char> val(toUTF8((*desc)->getDescription()));
117                                     auto_ptr_char lang((*desc)->getLang());
118                                     s += "\n  {\n  \"value\": \"";
119                                     s += val.get();
120                                     s += "\",\n  \"lang\": \"";
121                                     s += lang.get();
122                                     s += "\"\n  }";
123                                 }
124                                 s += "\n ]";
125                             }
126
127                             const vector<InformationURL*>& infurls = info->getInformationURLs();
128                             if (!infurls.empty()) {
129                                 s += ",\n \"InformationURLs\": [";
130                                 for (vector<InformationURL*>::const_iterator infurl = infurls.begin(); infurl != infurls.end(); ++infurl) {
131                                     if (infurl != infurls.begin())
132                                         s += ',';
133                                     auto_ptr_char val((*infurl)->getURL());
134                                     auto_ptr_char lang((*infurl)->getLang());
135                                     s += "\n  {\n  \"value\": \"";
136                                     s += val.get();
137                                     s += "\",\n  \"lang\": \"";
138                                     s += lang.get();
139                                     s += "\"\n  }";
140                                 }
141                                 s += "\n ]";
142                             }
143
144                             const vector<PrivacyStatementURL*>& privs = info->getPrivacyStatementURLs();
145                             if (!privs.empty()) {
146                                 s += ",\n \"PrivacyStatementURLs\": [";
147                                 for (vector<PrivacyStatementURL*>::const_iterator priv = privs.begin(); priv != privs.end(); ++priv) {
148                                     if (priv != privs.begin())
149                                         s += ',';
150                                     auto_ptr_char val((*priv)->getURL());
151                                     auto_ptr_char lang((*priv)->getLang());
152                                     s += "\n  {\n  \"value\": \"";
153                                     s += val.get();
154                                     s += "\",\n  \"lang\": \"";
155                                     s += lang.get();
156                                     s += "\"\n  }";
157                                 }
158                                 s += "\n ]";
159                             }
160
161                             const vector<Logo*>& logos = info->getLogos();
162                             if (!logos.empty()) {
163                                 s += ",\n \"Logos\": [";
164                                 for (vector<Logo*>::const_iterator logo = logos.begin(); logo != logos.end(); ++logo) {
165                                     if (logo != logos.begin())
166                                         s += ',';
167                                     s += "\n  {\n";
168                                     auto_ptr_char val((*logo)->getURL());
169                                     s += "  \"value\": \"";
170                                     s += val.get();
171                                     ostringstream ht;
172                                     ht << (*logo)->getHeight().second;
173                                     s += "\",\n  \"height\": \"";
174                                     s += ht.str();
175                                     ht.clear();
176                                     ht << (*logo)->getWidth().second;
177                                     s += "\",\n  \"width\": \"";
178                                     s += ht.str();
179                                     s += '\"';
180                                     if ((*logo)->getLang()) {
181                                         auto_ptr_char lang((*logo)->getLang());
182                                         s += ",\n  \"lang\": \"";
183                                         s += lang.get();
184                                         s += '\"';
185                                     }
186                                     s += "\n  }";
187                                 }
188                                 s += "\n ]";
189                             }
190                         }
191                     }
192                 }
193             }
194
195             if (m_legacyOrgNames && !extFound) {
196                 const Organization* org = nullptr;
197                 for (vector<IDPSSODescriptor*>::const_iterator idp = idps.begin(); !org && idp != idps.end(); ++idp) {
198                     if ((*idp)->isValid(now))
199                         org = (*idp)->getOrganization();
200                 }
201                 if (!org)
202                     org = entity->getOrganization();
203                 if (org) {
204                     const vector<OrganizationDisplayName*>& odns = org->getOrganizationDisplayNames();
205                     if (!odns.empty()) {
206                         s += ",\n \"DisplayNames\": [";
207                         for (vector<OrganizationDisplayName*>::const_iterator dispname = odns.begin(); dispname != odns.end(); ++dispname) {
208                             if (dispname != odns.begin())
209                                 s += ',';
210                             auto_arrayptr<char> val(toUTF8((*dispname)->getName()));
211                             auto_ptr_char lang((*dispname)->getLang());
212                             s += "\n  {\n  \"value\": \"";
213                             s += val.get();
214                             s += "\",\n  \"lang\": \"";
215                             s += lang.get();
216                             s += "\"\n  }";
217                         }
218                         s += "\n ]";
219                     }
220                 }
221             }
222
223             // Close the struct;
224             s += "\n}";
225         }
226     }
227 }
228
229 void DiscoverableMetadataProvider::disco(string& s, const EntitiesDescriptor* group, bool& first) const
230 {
231     if (group) {
232         const vector<EntitiesDescriptor*>& groups = group->getEntitiesDescriptors();
233         for (vector<EntitiesDescriptor*>::const_iterator i = groups.begin(); i != groups.end(); ++i)
234             disco(s, *i, first);
235
236         const vector<EntityDescriptor*>& sites = group->getEntityDescriptors();
237         for (vector<EntityDescriptor*>::const_iterator j = sites.begin(); j != sites.end(); ++j)
238             disco(s, *j, first);
239     }
240 }