Line | Count | Source |
1 | | /********************************************************************** |
2 | | * |
3 | | * Name: cpl_aws.h |
4 | | * Project: CPL - Common Portability Library |
5 | | * Purpose: Amazon Web Services routines |
6 | | * Author: Even Rouault <even.rouault at spatialys.com> |
7 | | * |
8 | | ********************************************************************** |
9 | | * Copyright (c) 2015, Even Rouault <even.rouault at spatialys.com> |
10 | | * |
11 | | * SPDX-License-Identifier: MIT |
12 | | ****************************************************************************/ |
13 | | |
14 | | #ifndef CPL_AWS_INCLUDED_H |
15 | | #define CPL_AWS_INCLUDED_H |
16 | | |
17 | | #ifndef DOXYGEN_SKIP |
18 | | |
19 | | #ifdef HAVE_CURL |
20 | | |
21 | | #include <cstddef> |
22 | | #include <mutex> |
23 | | |
24 | | #include "cpl_string.h" |
25 | | |
26 | | #include <curl/curl.h> |
27 | | #include <map> |
28 | | |
29 | | std::string CPLGetLowerCaseHexSHA256(const void *pabyData, size_t nBytes); |
30 | | std::string CPLGetLowerCaseHexSHA256(const std::string &osStr); |
31 | | |
32 | | std::string CPLGetAWS_SIGN4_Timestamp(GIntBig timestamp); |
33 | | |
34 | | std::string CPLAWSURLEncode(const std::string &osURL, bool bEncodeSlash = true); |
35 | | |
36 | | std::string CPLAWSGetHeaderVal(const struct curl_slist *psExistingHeaders, |
37 | | const char *pszKey); |
38 | | |
39 | | class IVSIS3LikeHandleHelper |
40 | | { |
41 | | CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandleHelper) |
42 | | |
43 | | protected: |
44 | | std::map<std::string, std::string> m_oMapQueryParameters{}; |
45 | | |
46 | | virtual void RebuildURL() = 0; |
47 | | std::string GetQueryString(bool bAddEmptyValueAfterEqual) const; |
48 | | |
49 | | public: |
50 | | IVSIS3LikeHandleHelper(); |
51 | | virtual ~IVSIS3LikeHandleHelper(); |
52 | | |
53 | | void ResetQueryParameters(); |
54 | | void AddQueryParameter(const std::string &osKey, |
55 | | const std::string &osValue); |
56 | | |
57 | | virtual struct curl_slist * |
58 | | GetCurlHeaders(const std::string &osVerb, struct curl_slist *psHeaders, |
59 | | const void *pabyDataContent = nullptr, |
60 | | size_t nBytesContent = 0) const = 0; |
61 | | |
62 | | virtual bool AllowAutomaticRedirection() |
63 | 0 | { |
64 | 0 | return true; |
65 | 0 | } |
66 | | |
67 | | virtual bool CanRestartOnError(const char *, const char * /* pszHeaders*/, |
68 | | bool /*bSetError*/) |
69 | 2.76k | { |
70 | 2.76k | return false; |
71 | 2.76k | } |
72 | | |
73 | | virtual const std::string &GetURL() const = 0; |
74 | | std::string GetURLNoKVP() const; |
75 | | |
76 | | virtual std::string GetCopySourceHeader() const |
77 | 0 | { |
78 | 0 | return std::string(); |
79 | 0 | } |
80 | | |
81 | | virtual const char *GetMetadataDirectiveREPLACE() const |
82 | 0 | { |
83 | 0 | return ""; |
84 | 0 | } |
85 | | |
86 | | static bool GetBucketAndObjectKey(const char *pszURI, |
87 | | const char *pszFSPrefix, |
88 | | bool bAllowNoObject, |
89 | | std::string &osBucketOut, |
90 | | std::string &osObjectKeyOut); |
91 | | |
92 | | static std::string BuildCanonicalizedHeaders( |
93 | | std::map<std::string, std::string> &oSortedMapHeaders, |
94 | | const struct curl_slist *psExistingHeaders, |
95 | | const char *pszHeaderPrefix); |
96 | | |
97 | | static std::string GetRFC822DateTime(); |
98 | | }; |
99 | | |
100 | | enum class AWSCredentialsSource |
101 | | { |
102 | | UNINITIALIZED, |
103 | | NO_SIGN_REQUEST, |
104 | | REGULAR, // credentials from env variables or ~/.aws/crediential |
105 | | EC2, // credentials from EC2 private networking |
106 | | WEB_IDENTITY, // credentials from Web Identity Token |
107 | | // See |
108 | | // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html |
109 | | ASSUMED_ROLE, // credentials from an STS assumed role |
110 | | // See |
111 | | // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-cli.html |
112 | | // and |
113 | | // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html |
114 | | SSO, // credentials from Single-Sign On |
115 | | // credentials from credential_process command |
116 | | // See https://docs.aws.amazon.com/sdkref/latest/guide/feature-process-credentials.html |
117 | | CREDENTIAL_PROCESS, |
118 | | NASA_EARTHDATA, // credentials from Nasa Earthdata login mechanism |
119 | | }; |
120 | | |
121 | | class VSIS3HandleHelper final : public IVSIS3LikeHandleHelper |
122 | | { |
123 | | CPL_DISALLOW_COPY_ASSIGN(VSIS3HandleHelper) |
124 | | |
125 | | std::string m_osURL{}; |
126 | | std::string m_osService{}; |
127 | | mutable std::string m_osSecretAccessKey{}; |
128 | | mutable std::string m_osAccessKeyId{}; |
129 | | mutable std::string m_osSessionToken{}; |
130 | | std::string m_osS3SessionToken{}; |
131 | | std::string m_osEndpoint{}; |
132 | | std::string m_osRegion{}; |
133 | | std::string m_osRequestPayer{}; |
134 | | std::string m_osBucket{}; |
135 | | std::string m_osObjectKey{}; |
136 | | bool m_bUseHTTPS = false; |
137 | | bool m_bUseVirtualHosting = false; |
138 | | bool m_bIsDirectoryBucket = false; |
139 | | AWSCredentialsSource m_eCredentialsSource = AWSCredentialsSource::REGULAR; |
140 | | |
141 | | void RebuildURL() override; |
142 | | |
143 | | static bool GetOrRefreshTemporaryCredentialsForRole( |
144 | | bool bForceRefresh, std::string &osSecretAccessKey, |
145 | | std::string &osAccessKeyId, std::string &osSessionToken, |
146 | | std::string &osRegion); |
147 | | |
148 | | static bool GetOrRefreshTemporaryCredentialsForSSO( |
149 | | bool bForceRefresh, std::string &osSecretAccessKey, |
150 | | std::string &osAccessKeyId, std::string &osSessionToken, |
151 | | std::string &osRegion); |
152 | | |
153 | | static bool GetOrRefreshTemporaryCredentialsFromProcess( |
154 | | bool bForceRefresh, std::string &osSecretAccessKey, |
155 | | std::string &osAccessKeyId, std::string &osSessionToken); |
156 | | |
157 | | static bool GetConfigurationFromAssumeRoleWithWebIdentity( |
158 | | bool bForceRefresh, const std::string &osPathForOption, |
159 | | const std::string &osRoleArnIn, |
160 | | const std::string &osWebIdentityTokenFileIn, |
161 | | std::string &osSecretAccessKey, std::string &osAccessKeyId, |
162 | | std::string &osSessionToken); |
163 | | |
164 | | static bool GetConfigurationFromEC2(bool bForceRefresh, |
165 | | const std::string &osPathForOption, |
166 | | std::string &osSecretAccessKey, |
167 | | std::string &osAccessKeyId, |
168 | | std::string &osSessionToken); |
169 | | |
170 | | static bool GetConfigurationFromAWSConfigFiles( |
171 | | const std::string &osPathForOption, const char *pszProfile, |
172 | | std::string &osSecretAccessKey, std::string &osAccessKeyId, |
173 | | std::string &osSessionToken, std::string &osRegion, |
174 | | std::string &osCredentials, std::string &osRoleArn, |
175 | | std::string &osSourceProfile, std::string &osExternalId, |
176 | | std::string &osMFASerial, std::string &osRoleSessionName, |
177 | | std::string &osWebIdentityTokenFile, std::string &osSSOStartURL, |
178 | | std::string &osSSOAccountID, std::string &osSSORoleName, |
179 | | std::string &osSSOSession, std::string &osCredentialProcess); |
180 | | |
181 | | static bool GetConfiguration(const std::string &osPathForOption, |
182 | | CSLConstList papszOptions, |
183 | | std::string &osSecretAccessKey, |
184 | | std::string &osAccessKeyId, |
185 | | std::string &osSessionToken, |
186 | | std::string &osRegion, |
187 | | AWSCredentialsSource &eCredentialsSource); |
188 | | |
189 | | void RefreshCredentials(const std::string &osPathForOption, |
190 | | bool bForceRefresh) const; |
191 | | |
192 | | protected: |
193 | | public: |
194 | | VSIS3HandleHelper( |
195 | | const std::string &osService, const std::string &osSecretAccessKey, |
196 | | const std::string &osAccessKeyId, const std::string &osSessionToken, |
197 | | const std::string &osS3SessionToken, const std::string &osEndpoint, |
198 | | const std::string &osRegion, const std::string &osRequestPayer, |
199 | | const std::string &osBucket, const std::string &osObjectKey, |
200 | | bool bUseHTTPS, bool bUseVirtualHosting, |
201 | | AWSCredentialsSource eCredentialsSource, bool bIsDirectoryBucket); |
202 | | ~VSIS3HandleHelper() override; |
203 | | |
204 | | static VSIS3HandleHelper *BuildFromURI(const char *pszURI, |
205 | | const char *pszFSPrefix, |
206 | | bool bAllowNoObject, |
207 | | CSLConstList papszOptions = nullptr); |
208 | | static std::string BuildURL(const std::string &osEndpoint, |
209 | | const std::string &osBucket, |
210 | | const std::string &osObjectKey, bool bUseHTTPS, |
211 | | bool bUseVirtualHosting); |
212 | | |
213 | | struct curl_slist *GetCurlHeaders(const std::string &osVerb, |
214 | | struct curl_slist *psHeaders, |
215 | | const void *pabyDataContent = nullptr, |
216 | | size_t nBytesContent = 0) const override; |
217 | | |
218 | | bool IsDirectoryBucket() const |
219 | 0 | { |
220 | 0 | return m_bIsDirectoryBucket; |
221 | 0 | } |
222 | | |
223 | | bool AllowAutomaticRedirection() override |
224 | 0 | { |
225 | 0 | return false; |
226 | 0 | } |
227 | | |
228 | | bool CanRestartOnError(const char *, const char *pszHeaders, |
229 | | bool bSetError) override; |
230 | | |
231 | | const std::string &GetURL() const override |
232 | 0 | { |
233 | 0 | return m_osURL; |
234 | 0 | } |
235 | | |
236 | | const std::string &GetBucket() const |
237 | 0 | { |
238 | 0 | return m_osBucket; |
239 | 0 | } |
240 | | |
241 | | const std::string &GetObjectKey() const |
242 | 0 | { |
243 | 0 | return m_osObjectKey; |
244 | 0 | } |
245 | | |
246 | | const std::string &GetEndpoint() const |
247 | 0 | { |
248 | 0 | return m_osEndpoint; |
249 | 0 | } |
250 | | |
251 | | const std::string &GetRegion() const |
252 | 0 | { |
253 | 0 | return m_osRegion; |
254 | 0 | } |
255 | | |
256 | | const std::string &GetAccessKeyId() const |
257 | 0 | { |
258 | 0 | return m_osAccessKeyId; |
259 | 0 | } |
260 | | |
261 | | const std::string &GetSecretAccessKey() const |
262 | 0 | { |
263 | 0 | return m_osSecretAccessKey; |
264 | 0 | } |
265 | | |
266 | | const std::string &GetSessionToken() const |
267 | 0 | { |
268 | 0 | return m_osSessionToken; |
269 | 0 | } |
270 | | |
271 | | AWSCredentialsSource GetCredentialsSource() const |
272 | 0 | { |
273 | 0 | return m_eCredentialsSource; |
274 | 0 | } |
275 | | |
276 | | const std::string &GetRequestPayer() const |
277 | 0 | { |
278 | 0 | return m_osRequestPayer; |
279 | 0 | } |
280 | | |
281 | | bool GetVirtualHosting() const |
282 | 0 | { |
283 | 0 | return m_bUseVirtualHosting; |
284 | 0 | } |
285 | | |
286 | | bool GetUseHTTPS() const |
287 | 0 | { |
288 | 0 | return m_bUseHTTPS; |
289 | 0 | } |
290 | | |
291 | | void SetEndpoint(const std::string &osStr); |
292 | | void SetRegion(const std::string &osStr); |
293 | | void SetRequestPayer(const std::string &osStr); |
294 | | void SetVirtualHosting(bool b); |
295 | | |
296 | | std::string GetCopySourceHeader() const override |
297 | 0 | { |
298 | 0 | return "x-amz-copy-source"; |
299 | 0 | } |
300 | | |
301 | | const char *GetMetadataDirectiveREPLACE() const override |
302 | 0 | { |
303 | 0 | return "x-amz-metadata-directive: REPLACE"; |
304 | 0 | } |
305 | | |
306 | | std::string GetSignedURL(CSLConstList papszOptions); |
307 | | |
308 | | static void CleanMutex(); |
309 | | static void ClearCache(); |
310 | | }; |
311 | | |
312 | | class VSIS3UpdateParams |
313 | | { |
314 | | private: |
315 | | std::string m_osRegion{}; |
316 | | std::string m_osEndpoint{}; |
317 | | std::string m_osRequestPayer{}; |
318 | | bool m_bUseVirtualHosting = false; |
319 | | |
320 | | explicit VSIS3UpdateParams(const VSIS3HandleHelper *poHelper) |
321 | 0 | : m_osRegion(poHelper->GetRegion()), |
322 | 0 | m_osEndpoint(poHelper->GetEndpoint()), |
323 | 0 | m_osRequestPayer(poHelper->GetRequestPayer()), |
324 | 0 | m_bUseVirtualHosting(poHelper->GetVirtualHosting()) |
325 | 0 | { |
326 | 0 | } |
327 | | |
328 | | void UpdateHandlerHelper(VSIS3HandleHelper *poHelper) |
329 | 0 | { |
330 | 0 | poHelper->SetRegion(m_osRegion); |
331 | 0 | poHelper->SetEndpoint(m_osEndpoint); |
332 | 0 | poHelper->SetRequestPayer(m_osRequestPayer); |
333 | 0 | poHelper->SetVirtualHosting(m_bUseVirtualHosting); |
334 | 0 | } |
335 | | |
336 | | static std::mutex gsMutex; |
337 | | static std::map<std::string, VSIS3UpdateParams> goMapBucketsToS3Params; |
338 | | |
339 | | public: |
340 | 0 | VSIS3UpdateParams() = default; |
341 | | |
342 | | static void UpdateMapFromHandle(VSIS3HandleHelper *poS3HandleHelper); |
343 | | static void UpdateHandleFromMap(VSIS3HandleHelper *poS3HandleHelper); |
344 | | static void ClearCache(); |
345 | | }; |
346 | | |
347 | | #endif /* HAVE_CURL */ |
348 | | |
349 | | #endif /* #ifndef DOXYGEN_SKIP */ |
350 | | |
351 | | #endif /* CPL_AWS_INCLUDED_H */ |