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 2186 : 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 : REGULAR, // credentials from env variables or ~/.aws/crediential
103 : EC2, // credentials from EC2 private networking
104 : WEB_IDENTITY, // credentials from Web Identity Token
105 : // See
106 : // https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html
107 : ASSUMED_ROLE, // credentials from an STS assumed role
108 : // See
109 : // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-cli.html
110 : // and
111 : // https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html
112 : SSO, // credentials from Single-Sign On
113 : };
114 :
115 : class VSIS3HandleHelper final : public IVSIS3LikeHandleHelper
116 : {
117 : CPL_DISALLOW_COPY_ASSIGN(VSIS3HandleHelper)
118 :
119 : std::string m_osURL{};
120 : std::string m_osService{};
121 : mutable std::string m_osSecretAccessKey{};
122 : mutable std::string m_osAccessKeyId{};
123 : mutable std::string m_osSessionToken{};
124 : std::string m_osS3SessionToken{};
125 : std::string m_osEndpoint{};
126 : std::string m_osRegion{};
127 : std::string m_osRequestPayer{};
128 : std::string m_osBucket{};
129 : std::string m_osObjectKey{};
130 : bool m_bUseHTTPS = false;
131 : bool m_bUseVirtualHosting = false;
132 : bool m_bIsDirectoryBucket = false;
133 : AWSCredentialsSource m_eCredentialsSource = AWSCredentialsSource::REGULAR;
134 :
135 : void RebuildURL() override;
136 :
137 : static bool GetOrRefreshTemporaryCredentialsForRole(
138 : bool bForceRefresh, std::string &osSecretAccessKey,
139 : std::string &osAccessKeyId, std::string &osSessionToken,
140 : std::string &osRegion);
141 :
142 : static bool GetOrRefreshTemporaryCredentialsForSSO(
143 : bool bForceRefresh, std::string &osSecretAccessKey,
144 : std::string &osAccessKeyId, std::string &osSessionToken,
145 : std::string &osRegion);
146 :
147 : static bool GetConfigurationFromAssumeRoleWithWebIdentity(
148 : bool bForceRefresh, const std::string &osPathForOption,
149 : const std::string &osRoleArnIn,
150 : const std::string &osWebIdentityTokenFileIn,
151 : std::string &osSecretAccessKey, std::string &osAccessKeyId,
152 : std::string &osSessionToken);
153 :
154 : static bool GetConfigurationFromEC2(bool bForceRefresh,
155 : const std::string &osPathForOption,
156 : std::string &osSecretAccessKey,
157 : std::string &osAccessKeyId,
158 : std::string &osSessionToken);
159 :
160 : static bool GetConfigurationFromAWSConfigFiles(
161 : const std::string &osPathForOption, const char *pszProfile,
162 : std::string &osSecretAccessKey, std::string &osAccessKeyId,
163 : std::string &osSessionToken, std::string &osRegion,
164 : std::string &osCredentials, std::string &osRoleArn,
165 : std::string &osSourceProfile, std::string &osExternalId,
166 : std::string &osMFASerial, std::string &osRoleSessionName,
167 : std::string &osWebIdentityTokenFile, std::string &osSSOStartURL,
168 : std::string &osSSOAccountID, std::string &osSSORoleName,
169 : std::string &osSSOSession);
170 :
171 : static bool GetConfiguration(const std::string &osPathForOption,
172 : CSLConstList papszOptions,
173 : std::string &osSecretAccessKey,
174 : std::string &osAccessKeyId,
175 : std::string &osSessionToken,
176 : std::string &osRegion,
177 : AWSCredentialsSource &eCredentialsSource);
178 :
179 : void RefreshCredentials(const std::string &osPathForOption,
180 : bool bForceRefresh) const;
181 :
182 : protected:
183 : public:
184 : VSIS3HandleHelper(
185 : const std::string &osService, const std::string &osSecretAccessKey,
186 : const std::string &osAccessKeyId, const std::string &osSessionToken,
187 : const std::string &osS3SessionToken, const std::string &osEndpoint,
188 : const std::string &osRegion, const std::string &osRequestPayer,
189 : const std::string &osBucket, const std::string &osObjectKey,
190 : bool bUseHTTPS, bool bUseVirtualHosting,
191 : AWSCredentialsSource eCredentialsSource, bool bIsDirectoryBucket);
192 : ~VSIS3HandleHelper();
193 :
194 : static VSIS3HandleHelper *BuildFromURI(const char *pszURI,
195 : const char *pszFSPrefix,
196 : bool bAllowNoObject,
197 : CSLConstList papszOptions = nullptr);
198 : static std::string BuildURL(const std::string &osEndpoint,
199 : const std::string &osBucket,
200 : const std::string &osObjectKey, bool bUseHTTPS,
201 : bool bUseVirtualHosting);
202 :
203 : struct curl_slist *GetCurlHeaders(const std::string &osVerb,
204 : struct curl_slist *psHeaders,
205 : const void *pabyDataContent = nullptr,
206 : size_t nBytesContent = 0) const override;
207 :
208 166 : bool IsDirectoryBucket() const
209 : {
210 166 : return m_bIsDirectoryBucket;
211 : }
212 :
213 141 : bool AllowAutomaticRedirection() override
214 : {
215 141 : return false;
216 : }
217 :
218 : bool CanRestartOnError(const char *, const char *pszHeaders,
219 : bool bSetError) override;
220 :
221 774 : const std::string &GetURL() const override
222 : {
223 774 : return m_osURL;
224 : }
225 :
226 569 : const std::string &GetBucket() const
227 : {
228 569 : return m_osBucket;
229 : }
230 :
231 0 : const std::string &GetObjectKey() const
232 : {
233 0 : return m_osObjectKey;
234 : }
235 :
236 13 : const std::string &GetEndpoint() const
237 : {
238 13 : return m_osEndpoint;
239 : }
240 :
241 13 : const std::string &GetRegion() const
242 : {
243 13 : return m_osRegion;
244 : }
245 :
246 13 : const std::string &GetRequestPayer() const
247 : {
248 13 : return m_osRequestPayer;
249 : }
250 :
251 13 : bool GetVirtualHosting() const
252 : {
253 13 : return m_bUseVirtualHosting;
254 : }
255 :
256 : void SetEndpoint(const std::string &osStr);
257 : void SetRegion(const std::string &osStr);
258 : void SetRequestPayer(const std::string &osStr);
259 : void SetVirtualHosting(bool b);
260 :
261 5 : std::string GetCopySourceHeader() const override
262 : {
263 5 : return "x-amz-copy-source";
264 : }
265 :
266 3 : const char *GetMetadataDirectiveREPLACE() const override
267 : {
268 3 : return "x-amz-metadata-directive: REPLACE";
269 : }
270 :
271 : std::string GetSignedURL(CSLConstList papszOptions);
272 :
273 : static void CleanMutex();
274 : static void ClearCache();
275 : };
276 :
277 : class VSIS3UpdateParams
278 : {
279 : private:
280 : std::string m_osRegion{};
281 : std::string m_osEndpoint{};
282 : std::string m_osRequestPayer{};
283 : bool m_bUseVirtualHosting = false;
284 :
285 13 : explicit VSIS3UpdateParams(const VSIS3HandleHelper *poHelper)
286 13 : : m_osRegion(poHelper->GetRegion()),
287 13 : m_osEndpoint(poHelper->GetEndpoint()),
288 13 : m_osRequestPayer(poHelper->GetRequestPayer()),
289 13 : m_bUseVirtualHosting(poHelper->GetVirtualHosting())
290 : {
291 13 : }
292 :
293 50 : void UpdateHandlerHelper(VSIS3HandleHelper *poHelper)
294 : {
295 50 : poHelper->SetRegion(m_osRegion);
296 50 : poHelper->SetEndpoint(m_osEndpoint);
297 50 : poHelper->SetRequestPayer(m_osRequestPayer);
298 50 : poHelper->SetVirtualHosting(m_bUseVirtualHosting);
299 50 : }
300 :
301 : static std::mutex gsMutex;
302 : static std::map<std::string, VSIS3UpdateParams> goMapBucketsToS3Params;
303 :
304 : public:
305 8 : VSIS3UpdateParams() = default;
306 :
307 : static void UpdateMapFromHandle(VSIS3HandleHelper *poS3HandleHelper);
308 : static void UpdateHandleFromMap(VSIS3HandleHelper *poS3HandleHelper);
309 : static void ClearCache();
310 : };
311 :
312 : #endif /* HAVE_CURL */
313 :
314 : #endif /* #ifndef DOXYGEN_SKIP */
315 :
316 : #endif /* CPL_AWS_INCLUDED_H */
|