Coverage Report

Created: 2026-08-14 09:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/port/cpl_aws.h
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 */