comparison Plugin/GoogleAccount.cpp @ 0:520cba9a0d42

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 13 Jun 2019 14:57:22 +0200
parents
children 798951e457f3
comparison
equal deleted inserted replaced
-1:000000000000 0:520cba9a0d42
1 /**
2 * Google Cloud Platform credentials for DICOMweb and Orthanc
3 * Copyright (C) 2019 Osimis S.A., Belgium
4 *
5 * This program is free software: you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * In addition, as a special exception, the copyright holders of this
11 * program give permission to link the code of its release with the
12 * OpenSSL project's "OpenSSL" library (or with modified versions of it
13 * that use the same license as the "OpenSSL" library), and distribute
14 * the linked executables. You must obey the GNU General Public License
15 * in all respects for all of the code used other than "OpenSSL". If you
16 * modify file(s) with this exception, you may extend this exception to
17 * your version of the file(s), but you are not obligated to do so. If
18 * you do not wish to do so, delete this exception statement from your
19 * version. If you delete this exception statement from all source files
20 * in the program, then also delete it here.
21 *
22 * This program is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 **/
30
31
32 #include "GoogleAccount.h"
33
34
35 void GoogleAccount::LoadAuthorizedUser(const std::string& json)
36 {
37 google::cloud::StatusOr<google::cloud::storage::oauth2::AuthorizedUserCredentialsInfo> info =
38 google::cloud::storage::oauth2::ParseAuthorizedUserCredentials(json, "memory");
39
40 if (!info)
41 {
42 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
43 "Cannot parse authorized user configuration");
44 }
45 else
46 {
47 type_ = Type_AuthorizedUser;
48 authorizedUser_.reset(new google::cloud::storage::oauth2::AuthorizedUserCredentialsInfo(*info));
49 }
50 }
51
52
53 bool GoogleAccount::LoadServiceAccount(const OrthancPlugins::OrthancConfiguration& account)
54 {
55 std::string path;
56
57 if (!account.LookupStringValue(path, "ServiceAccountFile"))
58 {
59 return false;
60 }
61
62 OrthancPlugins::MemoryBuffer f;
63 f.ReadFile(path);
64
65 std::string s;
66 f.ToString(s);
67
68 google::cloud::StatusOr<google::cloud::storage::oauth2::ServiceAccountCredentialsInfo> info =
69 google::cloud::storage::oauth2::ParseServiceAccountCredentials(s, "memory");
70
71 if (!info)
72 {
73 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
74 "Cannot parse service account configuration at: " + path);
75 }
76
77 type_ = Type_ServiceAccount;
78 serviceAccount_.reset(new google::cloud::storage::oauth2::ServiceAccountCredentialsInfo(*info));
79 return true;
80 }
81
82
83 bool GoogleAccount::LoadAuthorizedUserFile(const OrthancPlugins::OrthancConfiguration& account)
84 {
85 std::string path;
86
87 if (account.LookupStringValue(path, "AuthorizedUserFile"))
88 {
89 OrthancPlugins::MemoryBuffer f;
90 f.ReadFile(path);
91
92 std::string s;
93 f.ToString(s);
94
95 LoadAuthorizedUser(s);
96 return true;
97 }
98 else
99 {
100 return false;
101 }
102 }
103
104
105 bool GoogleAccount::LoadAuthorizedUserStrings(const OrthancPlugins::OrthancConfiguration& account)
106 {
107 std::string clientId, clientSecret, refreshToken;
108
109 if (account.LookupStringValue(clientId, "AuthorizedUserClientId") &&
110 account.LookupStringValue(clientSecret, "AuthorizedUserClientSecret") &&
111 account.LookupStringValue(refreshToken, "AuthorizedUserRefreshToken"))
112 {
113 Json::Value json = Json::objectValue;
114 json["client_id"] = clientId;
115 json["client_secret"] = clientSecret;
116 json["refresh_token"] = refreshToken;
117
118 LoadAuthorizedUser(json.toStyledString());
119 return true;
120 }
121 else
122 {
123 return false;
124 }
125 }
126
127
128 GoogleAccount::GoogleAccount(const OrthancPlugins::OrthancConfiguration& account,
129 const std::string& name) :
130 name_(name)
131 {
132 if (!account.LookupStringValue(project_, "Project"))
133 {
134 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
135 "Missing \"Project\" option for account \"" + name + "\"");
136 }
137
138 if (!account.LookupStringValue(location_, "Location"))
139 {
140 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
141 "Missing \"Location\" option for account \"" + name + "\"");
142 }
143
144 if (!account.LookupStringValue(dataset_, "Dataset"))
145 {
146 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
147 "Missing \"Dataset\" option for account \"" + name + "\"");
148 }
149
150 if (!account.LookupStringValue(dicomStore_, "DicomStore"))
151 {
152 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
153 "Missing \"DicomStore\" option for account \"" + name + "\"");
154 }
155
156 if (!LoadServiceAccount(account) &&
157 !LoadAuthorizedUserFile(account) &&
158 !LoadAuthorizedUserStrings(account))
159 {
160 throw Orthanc::OrthancException(
161 Orthanc::ErrorCode_BadFileFormat,
162 "Missing \"ServiceAccount\" or \"AuthorizedUserXXX\" option for account \"" + name + "\"");
163 }
164 }
165
166
167 const google::cloud::storage::oauth2::AuthorizedUserCredentialsInfo& GoogleAccount::GetAuthorizedUser() const
168 {
169 if (authorizedUser_.get() == NULL)
170 {
171 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
172 }
173 else
174 {
175 return *authorizedUser_;
176 }
177 }
178
179
180 google::cloud::storage::oauth2::ServiceAccountCredentialsInfo& GoogleAccount::GetServiceAccount() const
181 {
182 if (serviceAccount_.get() == NULL)
183 {
184 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
185 }
186 else
187 {
188 return *serviceAccount_;
189 }
190 }
191
192
193 static std::string AddTrailingSlash(const std::string& url)
194 {
195 // Add a trailing slash if needed
196 if (url.empty() ||
197 url[url.size() - 1] != '/')
198 {
199 return url + '/';
200 }
201 else
202 {
203 return url;
204 }
205 }
206
207
208 bool GoogleAccount::UpdateServerDefinition(const std::string& dicomWebPluginRoot,
209 const std::string& baseGoogleUrl,
210 const std::string& token) const
211 {
212 std::string url = (AddTrailingSlash(baseGoogleUrl) +
213 "projects/" + project_ +
214 "/locations/" + location_ +
215 "/datasets/" + dataset_ +
216 "/dicomStores/" + dicomStore_ +
217 "/dicomWeb/");
218
219 Json::Value headers = Json::objectValue;
220 headers["Authorization"] = "Bearer " + token;
221
222 Json::Value server = Json::objectValue;
223 server["Url"] = url;
224 server["HasDelete"] = "1"; // Google Cloud Platform allows "-X DELETE"
225 server["HttpHeaders"] = headers;
226
227 Json::Value answer;
228 if (OrthancPlugins::RestApiPut(answer, AddTrailingSlash(dicomWebPluginRoot) + "servers/" + name_,
229 server, true))
230 {
231 return true;
232 }
233 else
234 {
235 LOG(ERROR) << "Cannot update DICOMweb access to Google Cloud Platform: " << name_;
236 return false;
237 }
238 }