/src/gdal/port/cpl_swift.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | * Project: CPL - Common Portability Library |
3 | | * Purpose: OpenStack Swift Object Storage routines |
4 | | * Author: Even Rouault <even.rouault at spatialys.com> |
5 | | * |
6 | | ********************************************************************** |
7 | | * Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com> |
8 | | * |
9 | | * Permission is hereby granted, free of charge, to any person obtaining a |
10 | | * copy of this software and associated documentation files (the "Software"), |
11 | | * to deal in the Software without restriction, including without limitation |
12 | | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
13 | | * and/or sell copies of the Software, and to permit persons to whom the |
14 | | * Software is furnished to do so, subject to the following conditions: |
15 | | * |
16 | | * The above copyright notice and this permission notice shall be included |
17 | | * in all copies or substantial portions of the Software. |
18 | | * |
19 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
20 | | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
22 | | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
24 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
25 | | * DEALINSwift IN THE SOFTWARE. |
26 | | ****************************************************************************/ |
27 | | |
28 | | #include "cpl_swift.h" |
29 | | #include "cpl_vsi_error.h" |
30 | | #include "cpl_http.h" |
31 | | #include "cpl_multiproc.h" |
32 | | #include "cpl_json.h" |
33 | | |
34 | | // HOWTO setup a Docker-based SWIFT server: |
35 | | // https://github.com/MorrisJobke/docker-swift-onlyone |
36 | | |
37 | | //! @cond Doxygen_Suppress |
38 | | |
39 | | #ifdef HAVE_CURL |
40 | | |
41 | | static CPLMutex *g_hMutex = nullptr; |
42 | | static std::string g_osLastAuthURL; |
43 | | static std::string g_osLastUser; |
44 | | static std::string g_osLastKey; |
45 | | static std::string g_osLastStorageURL; |
46 | | static std::string g_osLastAuthToken; |
47 | | |
48 | | /************************************************************************/ |
49 | | /* GetSwiftHeaders() */ |
50 | | /************************************************************************/ |
51 | | |
52 | | static struct curl_slist *GetSwiftHeaders(const std::string &osAuthToken, |
53 | | struct curl_slist *headers) |
54 | 0 | { |
55 | 0 | headers = curl_slist_append(headers, "Accept: application/json"); |
56 | 0 | headers = curl_slist_append( |
57 | 0 | headers, CPLSPrintf("x-auth-token: %s", osAuthToken.c_str())); |
58 | 0 | return headers; |
59 | 0 | } |
60 | | |
61 | | /************************************************************************/ |
62 | | /* VSISwiftHandleHelper() */ |
63 | | /************************************************************************/ |
64 | | VSISwiftHandleHelper::VSISwiftHandleHelper(const std::string &osStorageURL, |
65 | | const std::string &osAuthToken, |
66 | | const std::string &osBucket, |
67 | | const std::string &osObjectKey) |
68 | 0 | : m_osURL(BuildURL(osStorageURL, osBucket, osObjectKey)), |
69 | 0 | m_osStorageURL(osStorageURL), m_osAuthToken(osAuthToken), |
70 | 0 | m_osBucket(osBucket), m_osObjectKey(osObjectKey) |
71 | 0 | { |
72 | 0 | } |
73 | | |
74 | | /************************************************************************/ |
75 | | /* ~VSISwiftHandleHelper() */ |
76 | | /************************************************************************/ |
77 | | |
78 | | VSISwiftHandleHelper::~VSISwiftHandleHelper() |
79 | 0 | { |
80 | 0 | } |
81 | | |
82 | | /************************************************************************/ |
83 | | /* GetConfiguration() */ |
84 | | /************************************************************************/ |
85 | | |
86 | | bool VSISwiftHandleHelper::GetConfiguration(const std::string &osPathForOption, |
87 | | std::string &osStorageURL, |
88 | | std::string &osAuthToken) |
89 | 23.9k | { |
90 | 23.9k | osStorageURL = VSIGetPathSpecificOption(osPathForOption.c_str(), |
91 | 23.9k | "SWIFT_STORAGE_URL", ""); |
92 | 23.9k | if (!osStorageURL.empty()) |
93 | 0 | { |
94 | 0 | osAuthToken = VSIGetPathSpecificOption(osPathForOption.c_str(), |
95 | 0 | "SWIFT_AUTH_TOKEN", ""); |
96 | 0 | if (osAuthToken.empty()) |
97 | 0 | { |
98 | 0 | const char *pszMsg = "Missing SWIFT_AUTH_TOKEN"; |
99 | 0 | CPLDebug("SWIFT", "%s", pszMsg); |
100 | 0 | VSIError(VSIE_InvalidCredentials, "%s", pszMsg); |
101 | 0 | return false; |
102 | 0 | } |
103 | 0 | return true; |
104 | 0 | } |
105 | | |
106 | 23.9k | const std::string osAuthVersion = VSIGetPathSpecificOption( |
107 | 23.9k | osPathForOption.c_str(), "OS_IDENTITY_API_VERSION", ""); |
108 | 23.9k | if (osAuthVersion == "3") |
109 | 0 | { |
110 | 0 | const std::string osAuthType = VSIGetPathSpecificOption( |
111 | 0 | osPathForOption.c_str(), "OS_AUTH_TYPE", ""); |
112 | 0 | if (!CheckCredentialsV3(osPathForOption, osAuthType)) |
113 | 0 | return false; |
114 | 0 | if (osAuthType == "v3applicationcredential") |
115 | 0 | { |
116 | 0 | if (GetCached(osPathForOption, "OS_AUTH_URL", |
117 | 0 | "OS_APPLICATION_CREDENTIAL_ID", |
118 | 0 | "OS_APPLICATION_CREDENTIAL_SECRET", osStorageURL, |
119 | 0 | osAuthToken)) |
120 | 0 | return true; |
121 | 0 | } |
122 | 0 | else |
123 | 0 | { |
124 | 0 | if (GetCached(osPathForOption, "OS_AUTH_URL", "OS_USERNAME", |
125 | 0 | "OS_PASSWORD", osStorageURL, osAuthToken)) |
126 | 0 | return true; |
127 | 0 | } |
128 | 0 | if (AuthV3(osPathForOption, osAuthType, osStorageURL, osAuthToken)) |
129 | 0 | return true; |
130 | 0 | } |
131 | 23.9k | else |
132 | 23.9k | { |
133 | 23.9k | const std::string osAuthV1URL = VSIGetPathSpecificOption( |
134 | 23.9k | osPathForOption.c_str(), "SWIFT_AUTH_V1_URL", ""); |
135 | 23.9k | if (!osAuthV1URL.empty()) |
136 | 0 | { |
137 | 0 | if (!CheckCredentialsV1(osPathForOption)) |
138 | 0 | return false; |
139 | 0 | if (GetCached(osPathForOption, "SWIFT_AUTH_V1_URL", "SWIFT_USER", |
140 | 0 | "SWIFT_KEY", osStorageURL, osAuthToken)) |
141 | 0 | return true; |
142 | 0 | if (AuthV1(osPathForOption, osStorageURL, osAuthToken)) |
143 | 0 | return true; |
144 | 0 | } |
145 | 23.9k | } |
146 | | |
147 | 23.9k | const char *pszMsg = "Missing SWIFT_STORAGE_URL+SWIFT_AUTH_TOKEN or " |
148 | 23.9k | "appropriate authentication options"; |
149 | 23.9k | CPLDebug("SWIFT", "%s", pszMsg); |
150 | 23.9k | VSIError(VSIE_InvalidCredentials, "%s", pszMsg); |
151 | | |
152 | 23.9k | return false; |
153 | 23.9k | } |
154 | | |
155 | | /************************************************************************/ |
156 | | /* AuthV1() */ |
157 | | /************************************************************************/ |
158 | | |
159 | | bool VSISwiftHandleHelper::AuthV1(const std::string &osPathForOption, |
160 | | std::string &osStorageURL, |
161 | | std::string &osAuthToken) |
162 | 0 | { |
163 | 0 | std::string osAuthURL = VSIGetPathSpecificOption(osPathForOption.c_str(), |
164 | 0 | "SWIFT_AUTH_V1_URL", ""); |
165 | 0 | std::string osUser = |
166 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_USER", ""); |
167 | 0 | std::string osKey = |
168 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_KEY", ""); |
169 | 0 | char **papszHeaders = |
170 | 0 | CSLSetNameValue(nullptr, "HEADERS", |
171 | 0 | CPLSPrintf("X-Auth-User: %s\r\n" |
172 | 0 | "X-Auth-Key: %s", |
173 | 0 | osUser.c_str(), osKey.c_str())); |
174 | 0 | CPLHTTPResult *psResult = CPLHTTPFetch(osAuthURL.c_str(), papszHeaders); |
175 | 0 | CSLDestroy(papszHeaders); |
176 | 0 | if (psResult == nullptr) |
177 | 0 | return false; |
178 | 0 | osStorageURL = |
179 | 0 | CSLFetchNameValueDef(psResult->papszHeaders, "X-Storage-Url", ""); |
180 | 0 | osAuthToken = |
181 | 0 | CSLFetchNameValueDef(psResult->papszHeaders, "X-Auth-Token", ""); |
182 | 0 | std::string osErrorMsg = |
183 | 0 | psResult->pabyData ? reinterpret_cast<const char *>(psResult->pabyData) |
184 | 0 | : ""; |
185 | 0 | CPLHTTPDestroyResult(psResult); |
186 | 0 | if (osStorageURL.empty() || osAuthToken.empty()) |
187 | 0 | { |
188 | 0 | CPLDebug("SWIFT", "Authentication failed: %s", osErrorMsg.c_str()); |
189 | 0 | VSIError(VSIE_InvalidCredentials, "Authentication failed: %s", |
190 | 0 | osErrorMsg.c_str()); |
191 | 0 | return false; |
192 | 0 | } |
193 | | |
194 | | // Cache credentials |
195 | 0 | { |
196 | 0 | CPLMutexHolder oHolder(&g_hMutex); |
197 | 0 | g_osLastAuthURL = std::move(osAuthURL); |
198 | 0 | g_osLastUser = std::move(osUser); |
199 | 0 | g_osLastKey = std::move(osKey); |
200 | 0 | g_osLastStorageURL = osStorageURL; |
201 | 0 | g_osLastAuthToken = osAuthToken; |
202 | 0 | } |
203 | |
|
204 | 0 | return true; |
205 | 0 | } |
206 | | |
207 | | /************************************************************************/ |
208 | | /* CreateAuthV3RequestObject() */ |
209 | | /************************************************************************/ |
210 | | |
211 | | CPLJSONObject VSISwiftHandleHelper::CreateAuthV3RequestObject( |
212 | | const std::string &osPathForOption, const std::string &osAuthType) |
213 | 0 | { |
214 | 0 | CPLJSONArray methods; |
215 | 0 | CPLJSONObject identity; |
216 | 0 | CPLJSONObject scope; |
217 | 0 | if (osAuthType == "v3applicationcredential") |
218 | 0 | { |
219 | 0 | std::string osApplicationCredentialID = VSIGetPathSpecificOption( |
220 | 0 | osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_ID", ""); |
221 | 0 | std::string osApplicationCredentialSecret = VSIGetPathSpecificOption( |
222 | 0 | osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_SECRET", ""); |
223 | 0 | CPLJSONObject applicationCredential; |
224 | 0 | applicationCredential.Add("id", osApplicationCredentialID); |
225 | 0 | applicationCredential.Add("secret", osApplicationCredentialSecret); |
226 | 0 | methods.Add("application_credential"); |
227 | 0 | identity.Add("application_credential", applicationCredential); |
228 | | // Application credentials cannot request a scope. |
229 | 0 | } |
230 | 0 | else |
231 | 0 | { |
232 | 0 | std::string osUser = VSIGetPathSpecificOption(osPathForOption.c_str(), |
233 | 0 | "OS_USERNAME", ""); |
234 | 0 | std::string osPassword = VSIGetPathSpecificOption( |
235 | 0 | osPathForOption.c_str(), "OS_PASSWORD", ""); |
236 | |
|
237 | 0 | CPLJSONObject user; |
238 | 0 | user.Add("name", osUser); |
239 | 0 | user.Add("password", osPassword); |
240 | |
|
241 | 0 | std::string osUserDomainName = VSIGetPathSpecificOption( |
242 | 0 | osPathForOption.c_str(), "OS_USER_DOMAIN_NAME", ""); |
243 | 0 | if (!osUserDomainName.empty()) |
244 | 0 | { |
245 | 0 | CPLJSONObject userDomain; |
246 | 0 | userDomain.Add("name", osUserDomainName); |
247 | 0 | user.Add("domain", userDomain); |
248 | 0 | } |
249 | |
|
250 | 0 | CPLJSONObject password; |
251 | 0 | password.Add("user", user); |
252 | 0 | methods.Add("password"); |
253 | 0 | identity.Add("password", password); |
254 | | |
255 | | // Request a scope if one is specified in the configuration |
256 | 0 | std::string osProjectName = VSIGetPathSpecificOption( |
257 | 0 | osPathForOption.c_str(), "OS_PROJECT_NAME", ""); |
258 | 0 | if (!osProjectName.empty()) |
259 | 0 | { |
260 | 0 | CPLJSONObject project; |
261 | 0 | project.Add("name", osProjectName); |
262 | |
|
263 | 0 | std::string osProjectDomainName = VSIGetPathSpecificOption( |
264 | 0 | osPathForOption.c_str(), "OS_PROJECT_DOMAIN_NAME", ""); |
265 | 0 | if (!osProjectDomainName.empty()) |
266 | 0 | { |
267 | 0 | CPLJSONObject projectDomain; |
268 | 0 | projectDomain.Add("name", osProjectDomainName); |
269 | 0 | project.Add("domain", projectDomain); |
270 | 0 | } |
271 | |
|
272 | 0 | scope.Add("project", project); |
273 | 0 | } |
274 | 0 | } |
275 | |
|
276 | 0 | identity.Add("methods", methods); |
277 | |
|
278 | 0 | CPLJSONObject auth; |
279 | 0 | auth.Add("identity", identity); |
280 | 0 | if (!scope.GetChildren().empty()) |
281 | 0 | auth.Add("scope", scope); |
282 | |
|
283 | 0 | CPLJSONObject obj; |
284 | 0 | obj.Add("auth", auth); |
285 | 0 | return obj; |
286 | 0 | } |
287 | | |
288 | | /************************************************************************/ |
289 | | /* GetAuthV3StorageURL() */ |
290 | | /************************************************************************/ |
291 | | |
292 | | bool VSISwiftHandleHelper::GetAuthV3StorageURL( |
293 | | const std::string &osPathForOption, const CPLHTTPResult *psResult, |
294 | | std::string &storageURL) |
295 | 0 | { |
296 | 0 | if (psResult->pabyData == nullptr) |
297 | 0 | return false; |
298 | | |
299 | 0 | CPLJSONDocument resultJson; |
300 | 0 | resultJson.LoadMemory(psResult->pabyData); |
301 | 0 | CPLJSONObject result(resultJson.GetRoot()); |
302 | |
|
303 | 0 | CPLJSONObject token(result.GetObj("token")); |
304 | 0 | if (!token.IsValid()) |
305 | 0 | return false; |
306 | | |
307 | 0 | CPLJSONArray catalog(token.GetArray("catalog")); |
308 | 0 | if (!catalog.IsValid()) |
309 | 0 | return false; |
310 | | |
311 | 0 | CPLJSONArray endpoints; |
312 | 0 | for (int i = 0; i < catalog.Size(); ++i) |
313 | 0 | { |
314 | 0 | CPLJSONObject item(catalog[i]); |
315 | 0 | if (item.GetString("type") == "object-store") |
316 | 0 | { |
317 | 0 | endpoints = item.GetArray("endpoints"); |
318 | 0 | break; |
319 | 0 | } |
320 | 0 | } |
321 | |
|
322 | 0 | if (endpoints.Size() == 0) |
323 | 0 | return false; |
324 | | |
325 | 0 | std::string osRegionName = |
326 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_REGION_NAME", ""); |
327 | 0 | if (osRegionName.empty()) |
328 | 0 | { |
329 | 0 | for (int i = 0; i < endpoints.Size(); ++i) |
330 | 0 | { |
331 | 0 | CPLJSONObject endpoint(endpoints[i]); |
332 | 0 | std::string interfaceType = |
333 | 0 | endpoint.GetString("interface", ""); // internal, admin, public |
334 | 0 | if (interfaceType.empty() || interfaceType == "public") |
335 | 0 | { |
336 | 0 | storageURL = endpoint.GetString("url"); |
337 | 0 | return true; |
338 | 0 | } |
339 | 0 | } |
340 | 0 | return false; |
341 | 0 | } |
342 | | |
343 | 0 | for (int i = 0; i < endpoints.Size(); ++i) |
344 | 0 | { |
345 | 0 | CPLJSONObject endpoint(endpoints[i]); |
346 | 0 | if (endpoint.GetString("region") == osRegionName) |
347 | 0 | { |
348 | 0 | std::string interfaceType = |
349 | 0 | endpoint.GetString("interface", ""); // internal, admin, public |
350 | 0 | if (interfaceType.empty() || interfaceType == "public") |
351 | 0 | { |
352 | 0 | storageURL = endpoint.GetString("url"); |
353 | 0 | CPLDebug("SWIFT", "Storage URL '%s' for region '%s'", |
354 | 0 | storageURL.c_str(), osRegionName.c_str()); |
355 | 0 | return true; |
356 | 0 | } |
357 | 0 | } |
358 | 0 | } |
359 | | |
360 | 0 | return false; |
361 | 0 | } |
362 | | |
363 | | /************************************************************************/ |
364 | | /* AuthV3() */ |
365 | | /************************************************************************/ |
366 | | |
367 | | bool VSISwiftHandleHelper::AuthV3(const std::string &osPathForOption, |
368 | | const std::string &osAuthType, |
369 | | std::string &osStorageURL, |
370 | | std::string &osAuthToken) |
371 | 0 | { |
372 | 0 | std::string osAuthID; |
373 | 0 | std::string osAuthKey; |
374 | 0 | if (osAuthType.empty() || osAuthType == "password") |
375 | 0 | { |
376 | 0 | osAuthID = VSIGetPathSpecificOption(osPathForOption.c_str(), |
377 | 0 | "OS_USERNAME", ""); |
378 | 0 | osAuthKey = VSIGetPathSpecificOption(osPathForOption.c_str(), |
379 | 0 | "OS_PASSWORD", ""); |
380 | 0 | } |
381 | 0 | else if (osAuthType == "v3applicationcredential") |
382 | 0 | { |
383 | 0 | osAuthID = VSIGetPathSpecificOption(osPathForOption.c_str(), |
384 | 0 | "OS_APPLICATION_CREDENTIAL_ID", ""); |
385 | 0 | osAuthKey = VSIGetPathSpecificOption( |
386 | 0 | osPathForOption.c_str(), "OS_APPLICATION_CREDENTIAL_SECRET", ""); |
387 | 0 | } |
388 | 0 | else |
389 | 0 | { |
390 | 0 | CPLDebug("SWIFT", "Unsupported OS SWIFT Auth Type: %s", |
391 | 0 | osAuthType.c_str()); |
392 | 0 | VSIError(VSIE_InvalidCredentials, "%s", osAuthType.c_str()); |
393 | 0 | return false; |
394 | 0 | } |
395 | 0 | CPLJSONObject postObject( |
396 | 0 | CreateAuthV3RequestObject(osPathForOption, osAuthType)); |
397 | 0 | std::string post = postObject.Format(CPLJSONObject::PrettyFormat::Plain); |
398 | | |
399 | | // coverity[tainted_data] |
400 | 0 | std::string osAuthURL = |
401 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_AUTH_URL", ""); |
402 | 0 | std::string url = osAuthURL; |
403 | 0 | if (!url.empty() && url.back() != '/') |
404 | 0 | url += '/'; |
405 | 0 | url += "auth/tokens"; |
406 | |
|
407 | 0 | char **papszOptions = CSLSetNameValue(nullptr, "POSTFIELDS", post.data()); |
408 | 0 | papszOptions = CSLSetNameValue(papszOptions, "HEADERS", |
409 | 0 | "Content-Type: application/json"); |
410 | 0 | CPLHTTPResult *psResult = CPLHTTPFetchEx(url.c_str(), papszOptions, nullptr, |
411 | 0 | nullptr, nullptr, nullptr); |
412 | 0 | CSLDestroy(papszOptions); |
413 | |
|
414 | 0 | if (psResult == nullptr) |
415 | 0 | return false; |
416 | | |
417 | 0 | osAuthToken = |
418 | 0 | CSLFetchNameValueDef(psResult->papszHeaders, "X-Subject-Token", ""); |
419 | |
|
420 | 0 | if (!GetAuthV3StorageURL(osPathForOption, psResult, osStorageURL)) |
421 | 0 | { |
422 | 0 | CPLHTTPDestroyResult(psResult); |
423 | 0 | return false; |
424 | 0 | } |
425 | | |
426 | 0 | if (osStorageURL.empty() || osAuthToken.empty()) |
427 | 0 | { |
428 | 0 | std::string osErrorMsg = |
429 | 0 | reinterpret_cast<const char *>(psResult->pabyData); |
430 | 0 | CPLDebug("SWIFT", "Authentication failed: %s", osErrorMsg.c_str()); |
431 | 0 | VSIError(VSIE_InvalidCredentials, "Authentication failed: %s", |
432 | 0 | osErrorMsg.c_str()); |
433 | 0 | CPLHTTPDestroyResult(psResult); |
434 | 0 | return false; |
435 | 0 | } |
436 | | |
437 | 0 | CPLHTTPDestroyResult(psResult); |
438 | | |
439 | | // Cache credentials |
440 | 0 | { |
441 | 0 | CPLMutexHolder oHolder(&g_hMutex); |
442 | 0 | g_osLastAuthURL = std::move(osAuthURL); |
443 | 0 | g_osLastUser = std::move(osAuthID); |
444 | 0 | g_osLastKey = std::move(osAuthKey); |
445 | 0 | g_osLastStorageURL = osStorageURL; |
446 | 0 | g_osLastAuthToken = osAuthToken; |
447 | 0 | } |
448 | 0 | return true; |
449 | 0 | } |
450 | | |
451 | | /************************************************************************/ |
452 | | /* Authenticate() */ |
453 | | /************************************************************************/ |
454 | | |
455 | | bool VSISwiftHandleHelper::Authenticate(const std::string &osPathForOption) |
456 | 0 | { |
457 | 0 | std::string osAuthV1URL = VSIGetPathSpecificOption(osPathForOption.c_str(), |
458 | 0 | "SWIFT_AUTH_V1_URL", ""); |
459 | 0 | if (!osAuthV1URL.empty() && |
460 | 0 | AuthV1(osPathForOption, m_osStorageURL, m_osAuthToken)) |
461 | 0 | { |
462 | 0 | RebuildURL(); |
463 | 0 | return true; |
464 | 0 | } |
465 | | |
466 | 0 | const std::string osAuthVersion = VSIGetPathSpecificOption( |
467 | 0 | osPathForOption.c_str(), "OS_IDENTITY_API_VERSION", ""); |
468 | 0 | const std::string osAuthType = |
469 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "OS_AUTH_TYPE", ""); |
470 | 0 | if (osAuthVersion == "3" && |
471 | 0 | AuthV3(osPathForOption, osAuthType, m_osStorageURL, m_osAuthToken)) |
472 | 0 | { |
473 | 0 | RebuildURL(); |
474 | 0 | return true; |
475 | 0 | } |
476 | | |
477 | 0 | return false; |
478 | 0 | } |
479 | | |
480 | | /************************************************************************/ |
481 | | /* CheckCredentialsV1() */ |
482 | | /************************************************************************/ |
483 | | |
484 | | bool VSISwiftHandleHelper::CheckCredentialsV1( |
485 | | const std::string &osPathForOption) |
486 | 0 | { |
487 | 0 | const char *pszMissingKey = nullptr; |
488 | 0 | std::string osUser = |
489 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_USER", ""); |
490 | 0 | std::string osKey = |
491 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), "SWIFT_KEY", ""); |
492 | 0 | if (osUser.empty()) |
493 | 0 | { |
494 | 0 | pszMissingKey = "SWIFT_USER"; |
495 | 0 | } |
496 | 0 | else if (osKey.empty()) |
497 | 0 | { |
498 | 0 | pszMissingKey = "SWIFT_KEY"; |
499 | 0 | } |
500 | |
|
501 | 0 | if (pszMissingKey) |
502 | 0 | { |
503 | 0 | CPLDebug("SWIFT", "Missing %s configuration option", pszMissingKey); |
504 | 0 | VSIError(VSIE_InvalidCredentials, "%s", pszMissingKey); |
505 | 0 | return false; |
506 | 0 | } |
507 | | |
508 | 0 | return true; |
509 | 0 | } |
510 | | |
511 | | /************************************************************************/ |
512 | | /* CheckCredentialsV3() */ |
513 | | /************************************************************************/ |
514 | | |
515 | | bool VSISwiftHandleHelper::CheckCredentialsV3( |
516 | | const std::string &osPathForOption, const std::string &osAuthType) |
517 | 0 | { |
518 | 0 | const char *papszMandatoryOptionKeys[3] = { |
519 | 0 | "OS_AUTH_URL", |
520 | 0 | "", |
521 | 0 | "", |
522 | 0 | }; |
523 | 0 | if (osAuthType.empty() || osAuthType == "password") |
524 | 0 | { |
525 | 0 | papszMandatoryOptionKeys[1] = "OS_USERNAME"; |
526 | 0 | papszMandatoryOptionKeys[2] = "OS_PASSWORD"; |
527 | 0 | } |
528 | 0 | else if (osAuthType == "v3applicationcredential") |
529 | 0 | { |
530 | 0 | papszMandatoryOptionKeys[1] = "OS_APPLICATION_CREDENTIAL_ID"; |
531 | 0 | papszMandatoryOptionKeys[2] = "OS_APPLICATION_CREDENTIAL_SECRET"; |
532 | 0 | } |
533 | 0 | else |
534 | 0 | { |
535 | 0 | CPLDebug("SWIFT", "Unsupported OS SWIFT Auth Type: %s", |
536 | 0 | osAuthType.c_str()); |
537 | 0 | VSIError(VSIE_InvalidCredentials, "%s", osAuthType.c_str()); |
538 | 0 | return false; |
539 | 0 | } |
540 | 0 | for (auto const *pszOptionKey : papszMandatoryOptionKeys) |
541 | 0 | { |
542 | 0 | std::string option = |
543 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), pszOptionKey, ""); |
544 | 0 | if (option.empty()) |
545 | 0 | { |
546 | 0 | CPLDebug("SWIFT", "Missing %s configuration option", pszOptionKey); |
547 | 0 | VSIError(VSIE_InvalidCredentials, "%s", pszOptionKey); |
548 | 0 | return false; |
549 | 0 | } |
550 | 0 | } |
551 | 0 | return true; |
552 | 0 | } |
553 | | |
554 | | /************************************************************************/ |
555 | | /* GetCached() */ |
556 | | /************************************************************************/ |
557 | | |
558 | | bool VSISwiftHandleHelper::GetCached(const std::string &osPathForOption, |
559 | | const char *pszURLKey, |
560 | | const char *pszUserKey, |
561 | | const char *pszPasswordKey, |
562 | | std::string &osStorageURL, |
563 | | std::string &osAuthToken) |
564 | 0 | { |
565 | 0 | std::string osAuthURL = |
566 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), pszURLKey, ""); |
567 | 0 | std::string osUser = |
568 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), pszUserKey, ""); |
569 | 0 | std::string osKey = |
570 | 0 | VSIGetPathSpecificOption(osPathForOption.c_str(), pszPasswordKey, ""); |
571 | |
|
572 | 0 | CPLMutexHolder oHolder(&g_hMutex); |
573 | | // Re-use cached credentials if available |
574 | | // coverity[tainted_data] |
575 | 0 | if (osAuthURL == g_osLastAuthURL && osUser == g_osLastUser && |
576 | 0 | osKey == g_osLastKey) |
577 | 0 | { |
578 | 0 | osStorageURL = g_osLastStorageURL; |
579 | 0 | osAuthToken = g_osLastAuthToken; |
580 | 0 | return true; |
581 | 0 | } |
582 | 0 | return false; |
583 | 0 | } |
584 | | |
585 | | /************************************************************************/ |
586 | | /* BuildFromURI() */ |
587 | | /************************************************************************/ |
588 | | |
589 | | VSISwiftHandleHelper * |
590 | | VSISwiftHandleHelper::BuildFromURI(const char *pszURI, |
591 | | const char * /*pszFSPrefix*/) |
592 | 23.9k | { |
593 | 23.9k | std::string osPathForOption("/vsiswift/"); |
594 | 23.9k | osPathForOption += pszURI; |
595 | | |
596 | 23.9k | std::string osStorageURL; |
597 | 23.9k | std::string osAuthToken; |
598 | | |
599 | 23.9k | if (!GetConfiguration(osPathForOption, osStorageURL, osAuthToken)) |
600 | 23.9k | { |
601 | 23.9k | return nullptr; |
602 | 23.9k | } |
603 | | |
604 | | // pszURI == bucket/object |
605 | 0 | const std::string osBucketObject(pszURI); |
606 | 0 | std::string osBucket(osBucketObject); |
607 | 0 | std::string osObjectKey; |
608 | 0 | size_t nSlashPos = osBucketObject.find('/'); |
609 | 0 | if (nSlashPos != std::string::npos) |
610 | 0 | { |
611 | 0 | osBucket = osBucketObject.substr(0, nSlashPos); |
612 | 0 | osObjectKey = osBucketObject.substr(nSlashPos + 1); |
613 | 0 | } |
614 | |
|
615 | 0 | return new VSISwiftHandleHelper(osStorageURL, osAuthToken, osBucket, |
616 | 0 | osObjectKey); |
617 | 23.9k | } |
618 | | |
619 | | /************************************************************************/ |
620 | | /* BuildURL() */ |
621 | | /************************************************************************/ |
622 | | |
623 | | std::string VSISwiftHandleHelper::BuildURL(const std::string &osStorageURL, |
624 | | const std::string &osBucket, |
625 | | const std::string &osObjectKey) |
626 | 0 | { |
627 | 0 | std::string osURL = osStorageURL; |
628 | 0 | if (!osBucket.empty()) |
629 | 0 | osURL += "/" + CPLAWSURLEncode(osBucket, false); |
630 | 0 | if (!osObjectKey.empty()) |
631 | 0 | osURL += "/" + CPLAWSURLEncode(osObjectKey, false); |
632 | 0 | return osURL; |
633 | 0 | } |
634 | | |
635 | | /************************************************************************/ |
636 | | /* RebuildURL() */ |
637 | | /************************************************************************/ |
638 | | |
639 | | void VSISwiftHandleHelper::RebuildURL() |
640 | 0 | { |
641 | 0 | m_osURL = BuildURL(m_osStorageURL, m_osBucket, m_osObjectKey); |
642 | 0 | m_osURL += GetQueryString(false); |
643 | 0 | } |
644 | | |
645 | | /************************************************************************/ |
646 | | /* GetCurlHeaders() */ |
647 | | /************************************************************************/ |
648 | | |
649 | | struct curl_slist *VSISwiftHandleHelper::GetCurlHeaders( |
650 | | const std::string &, struct curl_slist *headers, const void *, size_t) const |
651 | 0 | { |
652 | 0 | return GetSwiftHeaders(m_osAuthToken, headers); |
653 | 0 | } |
654 | | |
655 | | /************************************************************************/ |
656 | | /* CleanMutex() */ |
657 | | /************************************************************************/ |
658 | | |
659 | | void VSISwiftHandleHelper::CleanMutex() |
660 | 0 | { |
661 | 0 | if (g_hMutex != nullptr) |
662 | 0 | CPLDestroyMutex(g_hMutex); |
663 | 0 | g_hMutex = nullptr; |
664 | 0 | } |
665 | | |
666 | | /************************************************************************/ |
667 | | /* ClearCache() */ |
668 | | /************************************************************************/ |
669 | | |
670 | | void VSISwiftHandleHelper::ClearCache() |
671 | 0 | { |
672 | 0 | CPLMutexHolder oHolder(&g_hMutex); |
673 | 0 | g_osLastAuthURL.clear(); |
674 | 0 | g_osLastUser.clear(); |
675 | 0 | g_osLastKey.clear(); |
676 | 0 | g_osLastStorageURL.clear(); |
677 | 0 | g_osLastAuthToken.clear(); |
678 | 0 | } |
679 | | |
680 | | #endif |
681 | | |
682 | | //! @endcond |