Get rid of empty struct in each feed.
[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 <xmltooling/logging.h>
30 #include <xmltooling/XMLToolingConfig.h>
31
32 using namespace opensaml::saml2md;
33 using namespace xmltooling;
34 using namespace std;
35
36 namespace {
37     void disco(string& s, const EntityDescriptor* entity, bool first) {
38         if (entity) {
39             const vector<IDPSSODescriptor*>& idps = entity->getIDPSSODescriptors();
40             if (!idps.empty()) {
41                 auto_ptr_char entityid(entity->getEntityID());
42                 // Open a struct and output id: entityID.
43                 if (first)
44                     first = false;
45                 else
46                     s += ",\n";
47                 s += "{\n \"entityID\": \"";
48                 s += entityid.get();
49                 s += '\"';
50                 for (vector<IDPSSODescriptor*>::const_iterator idp = idps.begin(); idp != idps.end(); ++idp) {
51                     if ((*idp)->getExtensions()) {
52                         const vector<XMLObject*>& exts =  const_cast<const Extensions*>((*idp)->getExtensions())->getUnknownXMLObjects();
53                         for (vector<XMLObject*>::const_iterator ext = exts.begin(); ext != exts.end(); ++ext) {
54                             const UIInfo* info = dynamic_cast<UIInfo*>(*ext);
55                             if (info) {
56                                 const vector<DisplayName*>& dispnames = info->getDisplayNames();
57                                 if (!dispnames.empty()) {
58                                     s += ",\n \"DisplayNames\": [";
59                                     for (vector<DisplayName*>::const_iterator dispname = dispnames.begin(); dispname != dispnames.end(); ++dispname) {
60                                         if (dispname != dispnames.begin())
61                                             s += ',';
62                                         auto_ptr_char dn((*dispname)->getName());
63                                         auto_ptr_char lang((*dispname)->getLang());
64                                         s += "\n  {\n  \"value\": \"";
65                                         s += dn.get();
66                                         s += "\",\n  \"lang\": \"";
67                                         s += lang.get();
68                                         s += "\"\n  }";
69                                     }
70                                     s += "\n ]";
71                                 }
72
73                                 const vector<Description*>& descs = info->getDescriptions();
74                                 if (!descs.empty()) {
75                                     s += ",\n \"Descriptions\": [";
76                                     for (vector<Description*>::const_iterator desc = descs.begin(); desc != descs.end(); ++desc) {
77                                         if (desc != descs.begin())
78                                             s += ',';
79                                         auto_ptr_char d((*desc)->getDescription());
80                                         auto_ptr_char lang((*desc)->getLang());
81                                         s += "\n  {\n  \"value\": \"";
82                                         s += d.get();
83                                         s += "\",\n  \"lang\": \"";
84                                         s += lang.get();
85                                         s += "\"\n  }";
86                                     }
87                                     s += "\n ]";
88                                 }
89
90                                 const vector<InformationURL*>& infurls = info->getInformationURLs();
91                                 if (!infurls.empty()) {
92                                     s += ",\n \"InformationURLs\": [";
93                                     for (vector<InformationURL*>::const_iterator infurl = infurls.begin(); infurl != infurls.end(); ++infurl) {
94                                         if (infurl != infurls.begin())
95                                             s += ',';
96                                         auto_ptr_char iu((*infurl)->getURL());
97                                         auto_ptr_char lang((*infurl)->getLang());
98                                         s += "\n  {\n  \"value\": \"";
99                                         s += iu.get();
100                                         s += "\",\n  \"lang\": \"";
101                                         s += lang.get();
102                                         s += "\"\n  }";
103                                     }
104                                     s += "\n ]";
105                                 }
106
107                                 const vector<PrivacyStatementURL*>& privs = info->getPrivacyStatementURLs();
108                                 if (!privs.empty()) {
109                                     s += ",\n \"PrivacyStatementURLs\": [";
110                                     for (vector<PrivacyStatementURL*>::const_iterator priv = privs.begin(); priv != privs.end(); ++priv) {
111                                         if (priv != privs.begin())
112                                             s += ',';
113                                         auto_ptr_char pu((*priv)->getURL());
114                                         auto_ptr_char lang((*priv)->getLang());
115                                         s += "\n  {\n  \"value\": \"";
116                                         s += pu.get();
117                                         s += "\",\n  \"lang\": \"";
118                                         s += lang.get();
119                                         s += "\"\n  }";
120                                     }
121                                     s += "\n ]";
122                                 }
123
124                                 const vector<Logo*>& logos = info->getLogos();
125                                 if (!logos.empty()) {
126                                     s += ",\n \"Logos\": [";
127                                     for (vector<Logo*>::const_iterator logo = logos.begin(); logo != logos.end(); ++logo) {
128                                         if (logo != logos.begin())
129                                             s += ',';
130                                         s += "\n  {\n";
131                                         auto_ptr_char imgsrc((*logo)->getURL());
132                                         s += "  \"value\": \"";
133                                         s += imgsrc.get();
134                                         s += "\",\n  \"height\": \"";
135                                         s += (*logo)->getHeight().second;
136                                         s += "\",\n  \"width\": \"";
137                                         s += (*logo)->getWidth().second;
138                                         s += '\"';
139                                         if ((*logo)->getLang()) {
140                                             auto_ptr_char lang((*logo)->getLang());
141                                             s += ",\n  \"lang\": \"";
142                                             s += lang.get();
143                                             s += '\"';
144                                         }
145                                         s += "\n  }";
146                                     }
147                                     s += "\n ]";
148                                 }
149                             }
150                         }
151                     }
152                 }
153                 // Close the struct;
154                 s += "\n}";
155             }
156         }
157     }
158
159     void disco(string& s, const EntitiesDescriptor* group, bool first) {
160         if (group) {
161             const vector<EntitiesDescriptor*>& groups = group->getEntitiesDescriptors();
162             for (vector<EntitiesDescriptor*>::const_iterator i = groups.begin(); i != groups.end(); ++i)
163                 disco(s, *i, first);
164
165             const vector<EntityDescriptor*>& sites = group->getEntityDescriptors();
166             for (vector<EntityDescriptor*>::const_iterator j = sites.begin(); j != sites.end(); ++j)
167                 disco(s, *j, first);
168         }
169     }
170 }
171
172 DiscoverableMetadataProvider::DiscoverableMetadataProvider()
173 {
174 }
175
176 DiscoverableMetadataProvider::~DiscoverableMetadataProvider()
177 {
178 }
179
180 void DiscoverableMetadataProvider::generateFeed()
181 {
182     bool first = true;
183     m_feed = "[\n";
184     const XMLObject* object = getMetadata();
185     disco(m_feed, dynamic_cast<const EntitiesDescriptor*>(object), first);
186     disco(m_feed, dynamic_cast<const EntityDescriptor*>(object), first);
187     m_feed += "\n]\n";
188
189     SAMLConfig::getConfig().generateRandomBytes(m_feedTag, 4);
190     m_feedTag = SAMLArtifact::toHex(m_feedTag);
191 }
192
193 string DiscoverableMetadataProvider::getCacheTag() const
194 {
195     return m_feedTag;
196 }
197
198 ostream& DiscoverableMetadataProvider::outputFeed(ostream& os) const
199 {
200     return os << m_feed;
201 }