Coverage Report

Created: 2025-08-11 09:23

/src/gdal/port/cpl_aws.h
Line
Count
Source (jump to first uncovered line)
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
4.96k
    {
70
4.96k
        return false;
71
4.96k
    }
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
    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
    bool IsDirectoryBucket() const
209
0
    {
210
0
        return m_bIsDirectoryBucket;
211
0
    }
212
213
    bool AllowAutomaticRedirection() override
214
0
    {
215
0
        return false;
216
0
    }
217
218
    bool CanRestartOnError(const char *, const char *pszHeaders,
219
                           bool bSetError) override;
220
221
    const std::string &GetURL() const override
222
0
    {
223
0
        return m_osURL;
224
0
    }
225
226
    const std::string &GetBucket() const
227
0
    {
228
0
        return m_osBucket;
229
0
    }
230
231
    const std::string &GetObjectKey() const
232
0
    {
233
0
        return m_osObjectKey;
234
0
    }
235
236
    const std::string &GetEndpoint() const
237
0
    {
238
0
        return m_osEndpoint;
239
0
    }
240
241
    const std::string &GetRegion() const
242
0
    {
243
0
        return m_osRegion;
244
0
    }
245
246
    const std::string &GetRequestPayer() const
247
0
    {
248
0
        return m_osRequestPayer;
249
0
    }
250
251
    bool GetVirtualHosting() const
252
0
    {
253
0
        return m_bUseVirtualHosting;
254
0
    }
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
    std::string GetCopySourceHeader() const override
262
0
    {
263
0
        return "x-amz-copy-source";
264
0
    }
265
266
    const char *GetMetadataDirectiveREPLACE() const override
267
0
    {
268
0
        return "x-amz-metadata-directive: REPLACE";
269
0
    }
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
    explicit VSIS3UpdateParams(const VSIS3HandleHelper *poHelper)
286
0
        : m_osRegion(poHelper->GetRegion()),
287
0
          m_osEndpoint(poHelper->GetEndpoint()),
288
0
          m_osRequestPayer(poHelper->GetRequestPayer()),
289
0
          m_bUseVirtualHosting(poHelper->GetVirtualHosting())
290
0
    {
291
0
    }
292
293
    void UpdateHandlerHelper(VSIS3HandleHelper *poHelper)
294
0
    {
295
0
        poHelper->SetRegion(m_osRegion);
296
0
        poHelper->SetEndpoint(m_osEndpoint);
297
0
        poHelper->SetRequestPayer(m_osRequestPayer);
298
0
        poHelper->SetVirtualHosting(m_bUseVirtualHosting);
299
0
    }
300
301
    static std::mutex gsMutex;
302
    static std::map<std::string, VSIS3UpdateParams> goMapBucketsToS3Params;
303
304
  public:
305
0
    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 */