Line data Source code
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 3360 : 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 0 : virtual bool AllowAutomaticRedirection()
63 : {
64 0 : return true;
65 : }
66 :
67 2 : virtual bool CanRestartOnError(const char *, const char * /* pszHeaders*/,
68 : bool /*bSetError*/)
69 : {
70 2 : return false;
71 : }
72 :
73 : virtual const std::string &GetURL() const = 0;
74 : std::string GetURLNoKVP() const;
75 :
76 0 : virtual std::string GetCopySourceHeader() const
77 : {
78 0 : return std::string();
79 : }
80 :
81 0 : virtual const char *GetMetadataDirectiveREPLACE() const
82 : {
83 0 : return "";
84 : }
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 152 : bool IsDirectoryBucket() const
219 : {
220 152 : return m_bIsDirectoryBucket;
221 : }
222 :
223 188 : bool AllowAutomaticRedirection() override
224 : {
225 188 : return false;
226 : }
227 :
228 : bool CanRestartOnError(const char *, const char *pszHeaders,
229 : bool bSetError) override;
230 :
231 1199 : const std::string &GetURL() const override
232 : {
233 1199 : return m_osURL;
234 : }
235 :
236 1016 : const std::string &GetBucket() const
237 : {
238 1016 : return m_osBucket;
239 : }
240 :
241 0 : const std::string &GetObjectKey() const
242 : {
243 0 : return m_osObjectKey;
244 : }
245 :
246 16 : const std::string &GetEndpoint() const
247 : {
248 16 : return m_osEndpoint;
249 : }
250 :
251 16 : const std::string &GetRegion() const
252 : {
253 16 : return m_osRegion;
254 : }
255 :
256 : const std::string &GetAccessKeyId() const
257 : {
258 : return m_osAccessKeyId;
259 : }
260 :
261 : const std::string &GetSecretAccessKey() const
262 : {
263 : return m_osSecretAccessKey;
264 : }
265 :
266 : const std::string &GetSessionToken() const
267 : {
268 : return m_osSessionToken;
269 : }
270 :
271 : AWSCredentialsSource GetCredentialsSource() const
272 : {
273 : return m_eCredentialsSource;
274 : }
275 :
276 16 : const std::string &GetRequestPayer() const
277 : {
278 16 : return m_osRequestPayer;
279 : }
280 :
281 16 : bool GetVirtualHosting() const
282 : {
283 16 : return m_bUseVirtualHosting;
284 : }
285 :
286 : bool GetUseHTTPS() const
287 : {
288 : return m_bUseHTTPS;
289 : }
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 5 : std::string GetCopySourceHeader() const override
297 : {
298 5 : return "x-amz-copy-source";
299 : }
300 :
301 3 : const char *GetMetadataDirectiveREPLACE() const override
302 : {
303 3 : return "x-amz-metadata-directive: REPLACE";
304 : }
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 16 : explicit VSIS3UpdateParams(const VSIS3HandleHelper *poHelper)
321 16 : : m_osRegion(poHelper->GetRegion()),
322 16 : m_osEndpoint(poHelper->GetEndpoint()),
323 16 : m_osRequestPayer(poHelper->GetRequestPayer()),
324 16 : m_bUseVirtualHosting(poHelper->GetVirtualHosting())
325 : {
326 16 : }
327 :
328 113 : void UpdateHandlerHelper(VSIS3HandleHelper *poHelper)
329 : {
330 113 : poHelper->SetRegion(m_osRegion);
331 113 : poHelper->SetEndpoint(m_osEndpoint);
332 113 : poHelper->SetRequestPayer(m_osRequestPayer);
333 113 : poHelper->SetVirtualHosting(m_bUseVirtualHosting);
334 113 : }
335 :
336 : static std::mutex gsMutex;
337 : static std::map<std::string, VSIS3UpdateParams> goMapBucketsToS3Params;
338 :
339 : public:
340 11 : 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 */
|