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 : std::string CPLGetAWS_SIGN4_Signature(
40 : const std::string &osSecretAccessKey, const std::string &osAccessToken,
41 : const std::string &osRegion, const std::string &osRequestPayer,
42 : const std::string &osService, const std::string &osVerb,
43 : const struct curl_slist *psExistingHeaders, const std::string &osHost,
44 : const std::string &osCanonicalURI,
45 : const std::string &osCanonicalQueryString,
46 : const std::string &osXAMZContentSHA256, bool bAddHeaderAMZContentSHA256,
47 : const std::string &osTimestamp, std::string &osSignedHeaders);
48 :
49 : std::string CPLGetAWS_SIGN4_Authorization(
50 : const std::string &osSecretAccessKey, const std::string &osAccessKeyId,
51 : const std::string &osAccessToken, const std::string &osRegion,
52 : const std::string &osRequestPayer, const std::string &osService,
53 : const std::string &osVerb, const struct curl_slist *psExistingHeaders,
54 : const std::string &osHost, const std::string &osCanonicalURI,
55 : const std::string &osCanonicalQueryString,
56 : const std::string &osXAMZContentSHA256, bool bAddHeaderAMZContentSHA256,
57 : const std::string &osTimestamp);
58 :
59 : class IVSIS3LikeHandleHelper
60 : {
61 : CPL_DISALLOW_COPY_ASSIGN(IVSIS3LikeHandleHelper)
62 :
63 : protected:
64 : std::map<std::string, std::string> m_oMapQueryParameters{};
65 :
66 : virtual void RebuildURL() = 0;
67 : std::string GetQueryString(bool bAddEmptyValueAfterEqual) const;
68 :
69 : public:
70 984 : IVSIS3LikeHandleHelper() = default;
71 984 : virtual ~IVSIS3LikeHandleHelper() = default;
72 :
73 : void ResetQueryParameters();
74 : void AddQueryParameter(const std::string &osKey,
75 : const std::string &osValue);
76 :
77 : virtual struct curl_slist *
78 : GetCurlHeaders(const std::string &osVerb,
79 : const struct curl_slist *psExistingHeaders,
80 : const void *pabyDataContent = nullptr,
81 : size_t nBytesContent = 0) const = 0;
82 :
83 0 : virtual bool AllowAutomaticRedirection()
84 : {
85 0 : return true;
86 : }
87 :
88 2 : virtual bool CanRestartOnError(const char *, const char * /* pszHeaders*/,
89 : bool /*bSetError*/)
90 : {
91 2 : return false;
92 : }
93 :
94 : virtual const std::string &GetURL() const = 0;
95 : std::string GetURLNoKVP() const;
96 :
97 0 : virtual std::string GetCopySourceHeader() const
98 : {
99 0 : return std::string();
100 : }
101 :
102 0 : virtual const char *GetMetadataDirectiveREPLACE() const
103 : {
104 0 : return "";
105 : }
106 :
107 : static bool GetBucketAndObjectKey(const char *pszURI,
108 : const char *pszFSPrefix,
109 : bool bAllowNoObject,
110 : std::string &osBucketOut,
111 : std::string &osObjectKeyOut);
112 :
113 : static std::string BuildCanonicalizedHeaders(
114 : std::map<std::string, std::string> &oSortedMapHeaders,
115 : const struct curl_slist *psExistingHeaders,
116 : const char *pszHeaderPrefix);
117 :
118 : static std::string GetRFC822DateTime();
119 : };
120 :
121 : enum class AWSCredentialsSource
122 : {
123 : REGULAR, // credentials from env variables or ~/.aws/crediential
124 : EC2, // credentials from EC2 private networking
125 : WEB_IDENTITY, // credentials from Web Identity Token
126 : // See
127 : // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
128 : ASSUMED_ROLE, // credentials from an STS assumed role
129 : // See
130 : // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-cli.html
131 : // and
132 : // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html
133 : SSO, // credentials from Single-Sign On
134 : };
135 :
136 : class VSIS3HandleHelper final : public IVSIS3LikeHandleHelper
137 : {
138 : CPL_DISALLOW_COPY_ASSIGN(VSIS3HandleHelper)
139 :
140 : std::string m_osURL{};
141 : mutable std::string m_osSecretAccessKey{};
142 : mutable std::string m_osAccessKeyId{};
143 : mutable std::string m_osSessionToken{};
144 : std::string m_osEndpoint{};
145 : std::string m_osRegion{};
146 : std::string m_osRequestPayer{};
147 : std::string m_osBucket{};
148 : std::string m_osObjectKey{};
149 : bool m_bUseHTTPS = false;
150 : bool m_bUseVirtualHosting = false;
151 : AWSCredentialsSource m_eCredentialsSource = AWSCredentialsSource::REGULAR;
152 :
153 : void RebuildURL() override;
154 :
155 : static bool GetOrRefreshTemporaryCredentialsForRole(
156 : bool bForceRefresh, std::string &osSecretAccessKey,
157 : std::string &osAccessKeyId, std::string &osSessionToken,
158 : std::string &osRegion);
159 :
160 : static bool GetOrRefreshTemporaryCredentialsForSSO(
161 : bool bForceRefresh, std::string &osSecretAccessKey,
162 : std::string &osAccessKeyId, std::string &osSessionToken,
163 : std::string &osRegion);
164 :
165 : static bool GetConfigurationFromAssumeRoleWithWebIdentity(
166 : bool bForceRefresh, const std::string &osPathForOption,
167 : const std::string &osRoleArnIn,
168 : const std::string &osWebIdentityTokenFileIn,
169 : std::string &osSecretAccessKey, std::string &osAccessKeyId,
170 : std::string &osSessionToken);
171 :
172 : static bool GetConfigurationFromEC2(bool bForceRefresh,
173 : const std::string &osPathForOption,
174 : std::string &osSecretAccessKey,
175 : std::string &osAccessKeyId,
176 : std::string &osSessionToken);
177 :
178 : static bool GetConfigurationFromAWSConfigFiles(
179 : const std::string &osPathForOption, const char *pszProfile,
180 : std::string &osSecretAccessKey, std::string &osAccessKeyId,
181 : std::string &osSessionToken, std::string &osRegion,
182 : std::string &osCredentials, std::string &osRoleArn,
183 : std::string &osSourceProfile, std::string &osExternalId,
184 : std::string &osMFASerial, std::string &osRoleSessionName,
185 : std::string &osWebIdentityTokenFile, std::string &osSSOStartURL,
186 : std::string &osSSOAccountID, std::string &osSSORoleName);
187 :
188 : static bool GetConfiguration(const std::string &osPathForOption,
189 : CSLConstList papszOptions,
190 : std::string &osSecretAccessKey,
191 : std::string &osAccessKeyId,
192 : std::string &osSessionToken,
193 : std::string &osRegion,
194 : AWSCredentialsSource &eCredentialsSource);
195 :
196 : void RefreshCredentials(const std::string &osPathForOption,
197 : bool bForceRefresh) const;
198 :
199 : protected:
200 : public:
201 : VSIS3HandleHelper(
202 : const std::string &osSecretAccessKey, const std::string &osAccessKeyId,
203 : const std::string &osSessionToken, const std::string &osEndpoint,
204 : const std::string &osRegion, const std::string &osRequestPayer,
205 : const std::string &osBucket, const std::string &osObjectKey,
206 : bool bUseHTTPS, bool bUseVirtualHosting,
207 : AWSCredentialsSource eCredentialsSource);
208 : ~VSIS3HandleHelper();
209 :
210 : static VSIS3HandleHelper *BuildFromURI(const char *pszURI,
211 : const char *pszFSPrefix,
212 : bool bAllowNoObject,
213 : CSLConstList papszOptions = nullptr);
214 : static std::string BuildURL(const std::string &osEndpoint,
215 : const std::string &osBucket,
216 : const std::string &osObjectKey, bool bUseHTTPS,
217 : bool bUseVirtualHosting);
218 :
219 : struct curl_slist *
220 : GetCurlHeaders(const std::string &osVerb,
221 : const struct curl_slist *psExistingHeaders,
222 : const void *pabyDataContent = nullptr,
223 : size_t nBytesContent = 0) const override;
224 :
225 141 : bool AllowAutomaticRedirection() override
226 : {
227 141 : return false;
228 : }
229 :
230 : bool CanRestartOnError(const char *, const char *pszHeaders,
231 : bool bSetError) override;
232 :
233 816 : const std::string &GetURL() const override
234 : {
235 816 : return m_osURL;
236 : }
237 :
238 478 : const std::string &GetBucket() const
239 : {
240 478 : return m_osBucket;
241 : }
242 :
243 : const std::string &GetObjectKey() const
244 : {
245 : return m_osObjectKey;
246 : }
247 :
248 14 : const std::string &GetEndpoint() const
249 : {
250 14 : return m_osEndpoint;
251 : }
252 :
253 14 : const std::string &GetRegion() const
254 : {
255 14 : return m_osRegion;
256 : }
257 :
258 14 : const std::string &GetRequestPayer() const
259 : {
260 14 : return m_osRequestPayer;
261 : }
262 :
263 14 : bool GetVirtualHosting() const
264 : {
265 14 : return m_bUseVirtualHosting;
266 : }
267 :
268 : void SetEndpoint(const std::string &osStr);
269 : void SetRegion(const std::string &osStr);
270 : void SetRequestPayer(const std::string &osStr);
271 : void SetVirtualHosting(bool b);
272 :
273 5 : std::string GetCopySourceHeader() const override
274 : {
275 5 : return "x-amz-copy-source";
276 : }
277 :
278 3 : const char *GetMetadataDirectiveREPLACE() const override
279 : {
280 3 : return "x-amz-metadata-directive: REPLACE";
281 : }
282 :
283 : std::string GetSignedURL(CSLConstList papszOptions);
284 :
285 : static void CleanMutex();
286 : static void ClearCache();
287 : };
288 :
289 : class VSIS3UpdateParams
290 : {
291 : private:
292 : std::string m_osRegion{};
293 : std::string m_osEndpoint{};
294 : std::string m_osRequestPayer{};
295 : bool m_bUseVirtualHosting = false;
296 :
297 14 : explicit VSIS3UpdateParams(const VSIS3HandleHelper *poHelper)
298 14 : : m_osRegion(poHelper->GetRegion()),
299 14 : m_osEndpoint(poHelper->GetEndpoint()),
300 14 : m_osRequestPayer(poHelper->GetRequestPayer()),
301 14 : m_bUseVirtualHosting(poHelper->GetVirtualHosting())
302 : {
303 14 : }
304 :
305 52 : void UpdateHandlerHelper(VSIS3HandleHelper *poHelper)
306 : {
307 52 : poHelper->SetRegion(m_osRegion);
308 52 : poHelper->SetEndpoint(m_osEndpoint);
309 52 : poHelper->SetRequestPayer(m_osRequestPayer);
310 52 : poHelper->SetVirtualHosting(m_bUseVirtualHosting);
311 52 : }
312 :
313 : static std::mutex gsMutex;
314 : static std::map<std::string, VSIS3UpdateParams> goMapBucketsToS3Params;
315 :
316 : public:
317 9 : VSIS3UpdateParams() = default;
318 :
319 : static void UpdateMapFromHandle(VSIS3HandleHelper *poS3HandleHelper);
320 : static void UpdateHandleFromMap(VSIS3HandleHelper *poS3HandleHelper);
321 : static void ClearCache();
322 : };
323 :
324 : #endif /* HAVE_CURL */
325 :
326 : #endif /* #ifndef DOXYGEN_SKIP */
327 :
328 : #endif /* CPL_AWS_INCLUDED_H */
|