Mercurial > hg > orthanc-gcp
annotate Plugin/GoogleUpdater.cpp @ 54:509334672b6b default tip
updated copyright, as Orthanc Team now replaces Osimis
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 30 May 2024 22:48:01 +0200 |
parents | 21499c134785 |
children |
rev | line source |
---|---|
0 | 1 /** |
2 * Google Cloud Platform credentials for DICOMweb and Orthanc | |
54
509334672b6b
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
42
diff
changeset
|
3 * Copyright (C) 2019-2023 Osimis S.A., Belgium |
509334672b6b
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
42
diff
changeset
|
4 * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium |
509334672b6b
updated copyright, as Orthanc Team now replaces Osimis
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
42
diff
changeset
|
5 * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "GoogleUpdater.h" | |
35 | |
36 #include "GoogleConfiguration.h" | |
37 | |
40 | 38 #include <Logging.h> |
39 | |
0 | 40 #include <google/cloud/storage/internal/curl_handle_factory.h> |
41 #include <google/cloud/storage/oauth2/google_credentials.h> | |
42 | |
43 | |
44 namespace | |
45 { | |
46 class CurlBuilder : public google::cloud::storage::internal::CurlRequestBuilder | |
47 { | |
48 private: | |
49 class HandleFactory : public google::cloud::storage::internal::DefaultCurlHandleFactory | |
50 { | |
51 public: | |
52 google::cloud::storage::internal::CurlPtr CreateHandle() override | |
53 { | |
54 google::cloud::storage::internal::CurlPtr handle | |
55 (google::cloud::storage::internal::DefaultCurlHandleFactory::CreateHandle()); | |
56 | |
57 const GoogleConfiguration& configuration = GoogleConfiguration::GetInstance(); | |
58 | |
59 long timeout = static_cast<long>(configuration.GetTimeoutSeconds()); | |
60 | |
16
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
61 if (!configuration.GetCaInfo().empty() && |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
62 curl_easy_setopt(handle.get(), CURLOPT_CAINFO, configuration.GetCaInfo().c_str()) != CURLE_OK) |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
63 { |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
64 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
65 "Cannot set the trusted Certificate Authorities"); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
66 } |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
67 |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
68 bool ok; |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
69 |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
70 if (configuration.IsHttpsVerifyPeers()) |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
71 { |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
72 ok = (curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYHOST, 2) == CURLE_OK && |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
73 curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYPEER, 1) == CURLE_OK && |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
74 curl_easy_setopt(handle.get(), CURLOPT_TIMEOUT, timeout) == CURLE_OK); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
75 } |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
76 else |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
77 { |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
78 ok = (curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYHOST, 0) == CURLE_OK && |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
79 curl_easy_setopt(handle.get(), CURLOPT_SSL_VERIFYPEER, 0) == CURLE_OK); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
80 } |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
81 |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
82 if (!ok) |
0 | 83 { |
84 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | |
85 "Cannot initialize a libcurl handle"); | |
86 } | |
87 | |
88 return handle; | |
89 } | |
90 | |
91 google::cloud::storage::internal::CurlMulti CreateMultiHandle() override | |
92 { | |
93 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | |
94 } | |
95 }; | |
96 | |
97 public: | |
17 | 98 CurlBuilder(const std::string& base_url, |
99 const std::shared_ptr<google::cloud::storage::internal::CurlHandleFactory>& factory) : | |
0 | 100 CurlRequestBuilder(base_url, std::make_shared<HandleFactory>()) |
101 { | |
102 } | |
103 }; | |
104 } | |
105 | |
106 | |
107 | |
108 static boost::posix_time::ptime GetNow() | |
109 { | |
110 return boost::posix_time::second_clock::local_time(); | |
111 } | |
112 | |
113 | |
114 void GoogleUpdater::Worker(const State* state, | |
115 const GoogleAccount* account, | |
116 long refreshIntervalSeconds) | |
117 { | |
118 std::shared_ptr<google::cloud::storage::oauth2::Credentials> credentials; | |
119 | |
16
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
120 try |
0 | 121 { |
16
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
122 switch (account->GetType()) |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
123 { |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
124 case GoogleAccount::Type_ServiceAccount: |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
125 credentials = std::make_shared<google::cloud::storage::oauth2::ServiceAccountCredentials |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
126 <CurlBuilder>>(account->GetServiceAccount()); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
127 break; |
0 | 128 |
16
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
129 case GoogleAccount::Type_AuthorizedUser: |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
130 credentials = std::make_shared<google::cloud::storage::oauth2::AuthorizedUserCredentials |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
131 <CurlBuilder>>(account->GetAuthorizedUser()); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
132 break; |
0 | 133 |
16
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
134 default: |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
135 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
136 } |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
137 } |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
138 catch (Orthanc::OrthancException& e) |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
139 { |
25292488ff8f
using option HttpsVerifyPeers from Orthanc configuration
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
140 credentials.reset(); |
0 | 141 } |
142 | |
143 if (credentials.get() == NULL) | |
144 { | |
145 LOG(ERROR) << "Cannot initialize the token updater for Google Cloud Platform account: " | |
146 << account->GetName(); | |
147 return; | |
148 } | |
149 | |
150 const std::string dicomWebPluginRoot = GoogleConfiguration::GetInstance().GetDicomWebPluginRoot(); | |
151 const std::string baseGoogleUrl = GoogleConfiguration::GetInstance().GetBaseGoogleUrl(); | |
152 | |
153 std::string lastToken; | |
154 std::unique_ptr<boost::posix_time::ptime> lastUpdate; | |
155 | |
156 while (*state == State_Running) | |
157 { | |
158 if (lastUpdate.get() == NULL || | |
159 (GetNow() - *lastUpdate).total_seconds() >= refreshIntervalSeconds) | |
160 { | |
161 google::cloud::StatusOr<std::string> token = credentials->AuthorizationHeader(); | |
162 if (!token) | |
163 { | |
164 LOG(WARNING) << "Cannot generate Google Cloud Platform token for account: " << account->GetName(); | |
165 } | |
166 else if (*token != lastToken && | |
167 account->UpdateServerDefinition(dicomWebPluginRoot, baseGoogleUrl, *token)) | |
168 { | |
169 lastToken = *token; | |
170 } | |
171 | |
172 lastUpdate.reset(new boost::posix_time::ptime(GetNow())); | |
173 } | |
174 | |
175 boost::this_thread::sleep(boost::posix_time::milliseconds(100)); | |
176 } | |
177 } | |
178 | |
179 | |
180 GoogleUpdater::~GoogleUpdater() | |
181 { | |
182 if (state_ == State_Running) | |
183 { | |
184 LOG(ERROR) << "GoogleUpdater::Stop() should have been manually called"; | |
185 Stop(); | |
186 } | |
187 } | |
188 | |
189 | |
190 void GoogleUpdater::Start() | |
191 { | |
192 if (state_ != State_Setup) | |
193 { | |
194 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
195 } | |
196 | |
197 state_ = State_Running; | |
198 | |
199 const GoogleConfiguration& configuration = GoogleConfiguration::GetInstance(); | |
200 | |
201 workers_.resize(configuration.GetAccountsCount()); | |
202 | |
203 for (size_t i = 0; i < workers_.size(); i++) | |
204 { | |
205 workers_[i] = new boost::thread(Worker, &state_, &configuration.GetAccount(i), | |
206 configuration.GetRefreshIntervalSeconds()); | |
207 } | |
208 } | |
209 | |
210 | |
211 void GoogleUpdater::Stop() | |
212 { | |
213 if (state_ == State_Running) | |
214 { | |
215 state_ = State_Done; | |
216 | |
217 for (size_t i = 0; i < workers_.size(); i++) | |
218 { | |
219 if (workers_[i] != NULL) | |
220 { | |
221 if (workers_[i]->joinable()) | |
222 { | |
223 workers_[i]->join(); | |
224 } | |
225 | |
226 delete workers_[i]; | |
227 } | |
228 } | |
229 | |
230 workers_.clear(); | |
231 } | |
232 } |