]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_auth_s3.h
buildsys: switch source download to quincy
[ceph.git] / ceph / src / rgw / rgw_auth_s3.h
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae
FG
3
4#ifndef CEPH_RGW_AUTH_S3_H
5#define CEPH_RGW_AUTH_S3_H
6
31f18b77
FG
7#include <array>
8#include <memory>
7c673cae 9#include <string>
f67539c2 10#include <string_view>
7c673cae
FG
11#include <tuple>
12
31f18b77
FG
13#include <boost/algorithm/string.hpp>
14#include <boost/container/static_vector.hpp>
31f18b77
FG
15
16#include "common/sstring.hh"
7c673cae
FG
17#include "rgw_common.h"
18#include "rgw_rest_s3.h"
7c673cae
FG
19#include "rgw_auth.h"
20#include "rgw_auth_filters.h"
21#include "rgw_auth_keystone.h"
22
23
24namespace rgw {
25namespace auth {
26namespace s3 {
27
94b18763
FG
28static constexpr auto RGW_AUTH_GRACE = std::chrono::minutes{15};
29
30// returns true if the request time is within RGW_AUTH_GRACE of the current time
31bool is_time_skew_ok(time_t t);
32
11fdf7f2
TL
33class STSAuthStrategy : public rgw::auth::Strategy,
34 public rgw::auth::RemoteApplier::Factory,
35 public rgw::auth::LocalApplier::Factory,
36 public rgw::auth::RoleApplier::Factory {
37 typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
9f95a23c
TL
38 RGWCtl* const ctl;
39 rgw::auth::ImplicitTenants& implicit_tenant_context;
11fdf7f2
TL
40
41 STSEngine sts_engine;
42
43 aplptr_t create_apl_remote(CephContext* const cct,
44 const req_state* const s,
45 rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
46 const rgw::auth::RemoteApplier::AuthInfo &info
47 ) const override {
9f95a23c
TL
48 auto apl = rgw::auth::add_sysreq(cct, ctl, s,
49 rgw::auth::RemoteApplier(cct, ctl, std::move(acl_alg), info,
50 implicit_tenant_context,
51 rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3));
11fdf7f2
TL
52 return aplptr_t(new decltype(apl)(std::move(apl)));
53 }
54
55 aplptr_t create_apl_local(CephContext* const cct,
56 const req_state* const s,
57 const RGWUserInfo& user_info,
58 const std::string& subuser,
59 const boost::optional<uint32_t>& perm_mask) const override {
9f95a23c 60 auto apl = rgw::auth::add_sysreq(cct, ctl, s,
11fdf7f2
TL
61 rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask));
62 return aplptr_t(new decltype(apl)(std::move(apl)));
63 }
64
65 aplptr_t create_apl_role(CephContext* const cct,
66 const req_state* const s,
f91f0fd5 67 const rgw::auth::RoleApplier::Role& role,
11fdf7f2 68 const rgw_user& user_id,
f91f0fd5 69 const std::string& token_policy,
adb31ebb 70 const std::string& role_session_name,
f67539c2
TL
71 const std::vector<string>& token_claims,
72 const std::string& token_issued_at) const override {
9f95a23c 73 auto apl = rgw::auth::add_sysreq(cct, ctl, s,
f67539c2 74 rgw::auth::RoleApplier(cct, role, user_id, token_policy, role_session_name, token_claims, token_issued_at));
11fdf7f2
TL
75 return aplptr_t(new decltype(apl)(std::move(apl)));
76 }
77
78public:
79 STSAuthStrategy(CephContext* const cct,
9f95a23c
TL
80 RGWCtl* const ctl,
81 rgw::auth::ImplicitTenants& implicit_tenant_context,
11fdf7f2 82 AWSEngine::VersionAbstractor* const ver_abstractor)
9f95a23c
TL
83 : ctl(ctl),
84 implicit_tenant_context(implicit_tenant_context),
85 sts_engine(cct, ctl, *ver_abstractor,
11fdf7f2
TL
86 static_cast<rgw::auth::LocalApplier::Factory*>(this),
87 static_cast<rgw::auth::RemoteApplier::Factory*>(this),
88 static_cast<rgw::auth::RoleApplier::Factory*>(this)) {
89 if (cct->_conf->rgw_s3_auth_use_sts) {
90 add_engine(Control::SUFFICIENT, sts_engine);
91 }
92 }
93
94 const char* get_name() const noexcept override {
95 return "rgw::auth::s3::STSAuthStrategy";
96 }
97};
98
7c673cae
FG
99class ExternalAuthStrategy : public rgw::auth::Strategy,
100 public rgw::auth::RemoteApplier::Factory {
101 typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
9f95a23c
TL
102 RGWCtl* const ctl;
103 rgw::auth::ImplicitTenants& implicit_tenant_context;
7c673cae
FG
104
105 using keystone_config_t = rgw::keystone::CephCtxConfig;
106 using keystone_cache_t = rgw::keystone::TokenCache;
9f95a23c 107 using secret_cache_t = rgw::auth::keystone::SecretCache;
7c673cae
FG
108 using EC2Engine = rgw::auth::keystone::EC2Engine;
109
3efd9988 110 boost::optional <EC2Engine> keystone_engine;
7c673cae
FG
111 LDAPEngine ldap_engine;
112
113 aplptr_t create_apl_remote(CephContext* const cct,
114 const req_state* const s,
115 rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
11fdf7f2 116 const rgw::auth::RemoteApplier::AuthInfo &info
7c673cae 117 ) const override {
9f95a23c
TL
118 auto apl = rgw::auth::add_sysreq(cct, ctl, s,
119 rgw::auth::RemoteApplier(cct, ctl, std::move(acl_alg), info,
120 implicit_tenant_context,
121 rgw::auth::ImplicitTenants::IMPLICIT_TENANTS_S3));
7c673cae
FG
122 /* TODO(rzarzynski): replace with static_ptr. */
123 return aplptr_t(new decltype(apl)(std::move(apl)));
124 }
125
126public:
127 ExternalAuthStrategy(CephContext* const cct,
9f95a23c
TL
128 RGWCtl* const ctl,
129 rgw::auth::ImplicitTenants& implicit_tenant_context,
31f18b77 130 AWSEngine::VersionAbstractor* const ver_abstractor)
9f95a23c
TL
131 : ctl(ctl),
132 implicit_tenant_context(implicit_tenant_context),
133 ldap_engine(cct, ctl, *ver_abstractor,
7c673cae
FG
134 static_cast<rgw::auth::RemoteApplier::Factory*>(this)) {
135
136 if (cct->_conf->rgw_s3_auth_use_keystone &&
137 ! cct->_conf->rgw_keystone_url.empty()) {
3efd9988
FG
138
139 keystone_engine.emplace(cct, ver_abstractor,
140 static_cast<rgw::auth::RemoteApplier::Factory*>(this),
141 keystone_config_t::get_instance(),
9f95a23c
TL
142 keystone_cache_t::get_instance<keystone_config_t>(),
143 secret_cache_t::get_instance());
3efd9988
FG
144 add_engine(Control::SUFFICIENT, *keystone_engine);
145
7c673cae
FG
146 }
147
a8e16298 148 if (ldap_engine.valid()) {
7c673cae
FG
149 add_engine(Control::SUFFICIENT, ldap_engine);
150 }
151 }
152
153 const char* get_name() const noexcept override {
154 return "rgw::auth::s3::AWSv2ExternalAuthStrategy";
155 }
156};
157
158
d2e6a577
FG
159template <class AbstractorT,
160 bool AllowAnonAccessT = false>
31f18b77
FG
161class AWSAuthStrategy : public rgw::auth::Strategy,
162 public rgw::auth::LocalApplier::Factory {
7c673cae
FG
163 typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
164
31f18b77
FG
165 static_assert(std::is_base_of<rgw::auth::s3::AWSEngine::VersionAbstractor,
166 AbstractorT>::value,
167 "AbstractorT must be a subclass of rgw::auth::s3::VersionAbstractor");
7c673cae 168
9f95a23c 169 RGWCtl* const ctl;
31f18b77 170 AbstractorT ver_abstractor;
7c673cae 171
d2e6a577 172 S3AnonymousEngine anonymous_engine;
7c673cae 173 ExternalAuthStrategy external_engines;
11fdf7f2 174 STSAuthStrategy sts_engine;
31f18b77 175 LocalEngine local_engine;
7c673cae
FG
176
177 aplptr_t create_apl_local(CephContext* const cct,
178 const req_state* const s,
179 const RGWUserInfo& user_info,
11fdf7f2
TL
180 const std::string& subuser,
181 const boost::optional<uint32_t>& perm_mask) const override {
9f95a23c 182 auto apl = rgw::auth::add_sysreq(cct, ctl, s,
11fdf7f2 183 rgw::auth::LocalApplier(cct, user_info, subuser, perm_mask));
7c673cae
FG
184 /* TODO(rzarzynski): replace with static_ptr. */
185 return aplptr_t(new decltype(apl)(std::move(apl)));
186 }
187
188public:
1adf2230
AA
189 using engine_map_t = std::map <std::string, std::reference_wrapper<const Engine>>;
190 void add_engines(const std::vector <std::string>& auth_order,
191 engine_map_t eng_map)
192 {
193 auto ctrl_flag = Control::SUFFICIENT;
194 for (const auto &eng : auth_order) {
195 // fallback to the last engine, in case of multiple engines, since ctrl
196 // flag is sufficient for others, error from earlier engine is returned
197 if (&eng == &auth_order.back() && eng_map.size() > 1) {
198 ctrl_flag = Control::FALLBACK;
199 }
11fdf7f2
TL
200 if (const auto kv = eng_map.find(eng);
201 kv != eng_map.end()) {
1adf2230
AA
202 add_engine(ctrl_flag, kv->second);
203 }
204 }
205 }
206
11fdf7f2 207 auto parse_auth_order(CephContext* const cct)
1adf2230
AA
208 {
209 std::vector <std::string> result;
210
11fdf7f2
TL
211 const std::set <std::string_view> allowed_auth = { "sts", "external", "local" };
212 std::vector <std::string> default_order = { "sts", "external", "local" };
1adf2230
AA
213 // supplied strings may contain a space, so let's bypass that
214 boost::split(result, cct->_conf->rgw_s3_auth_order,
215 boost::is_any_of(", "), boost::token_compress_on);
216
217 if (std::any_of(result.begin(), result.end(),
11fdf7f2 218 [allowed_auth](std::string_view s)
1adf2230
AA
219 { return allowed_auth.find(s) == allowed_auth.end();})){
220 return default_order;
221 }
222 return result;
223 }
224
31f18b77 225 AWSAuthStrategy(CephContext* const cct,
9f95a23c
TL
226 rgw::auth::ImplicitTenants& implicit_tenant_context,
227 RGWCtl* const ctl)
228 : ctl(ctl),
31f18b77 229 ver_abstractor(cct),
d2e6a577
FG
230 anonymous_engine(cct,
231 static_cast<rgw::auth::LocalApplier::Factory*>(this)),
9f95a23c
TL
232 external_engines(cct, ctl, implicit_tenant_context, &ver_abstractor),
233 sts_engine(cct, ctl, implicit_tenant_context, &ver_abstractor),
234 local_engine(cct, ctl, ver_abstractor,
7c673cae 235 static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
11fdf7f2 236 /* The anonymous auth. */
d2e6a577
FG
237 if (AllowAnonAccessT) {
238 add_engine(Control::SUFFICIENT, anonymous_engine);
239 }
7c673cae 240
1adf2230
AA
241 auto auth_order = parse_auth_order(cct);
242 engine_map_t engine_map;
11fdf7f2
TL
243
244 /* STS Auth*/
245 if (! sts_engine.is_empty()) {
246 engine_map.insert(std::make_pair("sts", std::cref(sts_engine)));
247 }
248
d2e6a577 249 /* The external auth. */
7c673cae 250 if (! external_engines.is_empty()) {
1adf2230 251 engine_map.insert(std::make_pair("external", std::cref(external_engines)));
7c673cae 252 }
d2e6a577 253 /* The local auth. */
7c673cae 254 if (cct->_conf->rgw_s3_auth_use_rados) {
1adf2230 255 engine_map.insert(std::make_pair("local", std::cref(local_engine)));
7c673cae 256 }
11fdf7f2 257
1adf2230 258 add_engines(auth_order, engine_map);
7c673cae
FG
259 }
260
261 const char* get_name() const noexcept override {
31f18b77 262 return "rgw::auth::s3::AWSAuthStrategy";
7c673cae
FG
263 }
264};
265
31f18b77
FG
266
267class AWSv4ComplMulti : public rgw::auth::Completer,
268 public rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>,
269 public std::enable_shared_from_this<AWSv4ComplMulti> {
270 using io_base_t = rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>;
11fdf7f2 271 using signing_key_t = sha256_digest_t;
31f18b77
FG
272
273 CephContext* const cct;
274
f67539c2
TL
275 const std::string_view date;
276 const std::string_view credential_scope;
31f18b77
FG
277 const signing_key_t signing_key;
278
279 class ChunkMeta {
280 size_t data_offset_in_stream = 0;
281 size_t data_length = 0;
282 std::string signature;
283
284 ChunkMeta(const size_t data_starts_in_stream,
285 const size_t data_length,
f67539c2 286 const std::string_view signature)
31f18b77
FG
287 : data_offset_in_stream(data_starts_in_stream),
288 data_length(data_length),
f67539c2 289 signature(std::string(signature)) {
31f18b77
FG
290 }
291
f67539c2
TL
292 explicit ChunkMeta(const std::string_view& signature)
293 : signature(std::string(signature)) {
31f18b77
FG
294 }
295
296 public:
297 static constexpr size_t SIG_SIZE = 64;
298
299 /* Let's suppose the data length fields can't exceed uint64_t. */
300 static constexpr size_t META_MAX_SIZE = \
301 sarrlen("\r\nffffffffffffffff;chunk-signature=") + SIG_SIZE + sarrlen("\r\n");
302
303 /* The metadata size of for the last, empty chunk. */
304 static constexpr size_t META_MIN_SIZE = \
305 sarrlen("0;chunk-signature=") + SIG_SIZE + sarrlen("\r\n");
306
307 /* Detect whether a given stream_pos fits in boundaries of a chunk. */
308 bool is_new_chunk_in_stream(size_t stream_pos) const;
309
310 /* Get the remaining data size. */
311 size_t get_data_size(size_t stream_pos) const;
312
313 const std::string& get_signature() const {
314 return signature;
315 }
316
317 /* Factory: create an object representing metadata of first, initial chunk
318 * in a stream. */
f67539c2 319 static ChunkMeta create_first(const std::string_view& seed_signature) {
31f18b77
FG
320 return ChunkMeta(seed_signature);
321 }
322
323 /* Factory: parse a block of META_MAX_SIZE bytes and creates an object
324 * representing non-first chunk in a stream. As the process is sequential
325 * and depends on the previous chunk, caller must pass it. */
326 static std::pair<ChunkMeta, size_t> create_next(CephContext* cct,
327 ChunkMeta&& prev,
328 const char* metabuf,
329 size_t metabuf_len);
330 } chunk_meta;
331
332 size_t stream_pos;
333 boost::container::static_vector<char, ChunkMeta::META_MAX_SIZE> parsing_buf;
334 ceph::crypto::SHA256* sha256_hash;
335 std::string prev_chunk_signature;
336
337 bool is_signature_mismatched();
338 std::string calc_chunk_signature(const std::string& payload_hash) const;
339
340public:
341 /* We need the constructor to be public because of the std::make_shared that
342 * is employed by the create() method. */
343 AWSv4ComplMulti(const req_state* const s,
f67539c2
TL
344 std::string_view date,
345 std::string_view credential_scope,
346 std::string_view seed_signature,
31f18b77
FG
347 const signing_key_t& signing_key)
348 : io_base_t(nullptr),
349 cct(s->cct),
350 date(std::move(date)),
351 credential_scope(std::move(credential_scope)),
352 signing_key(signing_key),
353
354 /* The evolving state. */
355 chunk_meta(ChunkMeta::create_first(seed_signature)),
356 stream_pos(0),
357 sha256_hash(calc_hash_sha256_open_stream()),
358 prev_chunk_signature(std::move(seed_signature)) {
359 }
360
361 ~AWSv4ComplMulti() {
362 if (sha256_hash) {
363 calc_hash_sha256_close_stream(&sha256_hash);
364 }
365 }
366
367 /* rgw::io::DecoratedRestfulClient. */
368 size_t recv_body(char* buf, size_t max) override;
369
370 /* rgw::auth::Completer. */
11fdf7f2 371 void modify_request_state(const DoutPrefixProvider* dpp, req_state* s_rw) override;
31f18b77
FG
372 bool complete() override;
373
374 /* Factories. */
375 static cmplptr_t create(const req_state* s,
f67539c2
TL
376 std::string_view date,
377 std::string_view credential_scope,
378 std::string_view seed_signature,
31f18b77
FG
379 const boost::optional<std::string>& secret_key);
380
381};
382
383class AWSv4ComplSingle : public rgw::auth::Completer,
384 public rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>,
385 public std::enable_shared_from_this<AWSv4ComplSingle> {
386 using io_base_t = rgw::io::DecoratedRestfulClient<rgw::io::RestfulClient*>;
387
388 CephContext* const cct;
389 const char* const expected_request_payload_hash;
390 ceph::crypto::SHA256* sha256_hash = nullptr;
391
392public:
393 /* Defined in rgw_auth_s3.cc because of get_v4_exp_payload_hash(). We need
394 * the constructor to be public because of the std::make_shared employed by
395 * the create() method. */
11fdf7f2 396 explicit AWSv4ComplSingle(const req_state* const s);
31f18b77
FG
397
398 ~AWSv4ComplSingle() {
399 if (sha256_hash) {
400 calc_hash_sha256_close_stream(&sha256_hash);
401 }
402 }
403
404 /* rgw::io::DecoratedRestfulClient. */
405 size_t recv_body(char* buf, size_t max) override;
406
407 /* rgw::auth::Completer. */
11fdf7f2 408 void modify_request_state(const DoutPrefixProvider* dpp, req_state* s_rw) override;
31f18b77
FG
409 bool complete() override;
410
411 /* Factories. */
412 static cmplptr_t create(const req_state* s,
413 const boost::optional<std::string>&);
414
415};
416
7c673cae
FG
417} /* namespace s3 */
418} /* namespace auth */
419} /* namespace rgw */
420
421void rgw_create_s3_canonical_header(
b3b6e05e 422 const DoutPrefixProvider *dpp,
7c673cae
FG
423 const char *method,
424 const char *content_md5,
425 const char *content_type,
426 const char *date,
9f95a23c
TL
427 const meta_map_t& meta_map,
428 const meta_map_t& qs_map,
7c673cae
FG
429 const char *request_uri,
430 const std::map<std::string, std::string>& sub_resources,
431 std::string& dest_str);
b3b6e05e
TL
432bool rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp,
433 const req_info& info,
7c673cae
FG
434 utime_t *header_time, /* out */
435 std::string& dest, /* out */
436 bool qsr);
437static inline std::tuple<bool, std::string, utime_t>
b3b6e05e 438rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp, const req_info& info, const bool qsr) {
7c673cae
FG
439 std::string dest;
440 utime_t header_time;
441
b3b6e05e 442 const bool ok = rgw_create_s3_canonical_header(dpp, info, &header_time, dest, qsr);
7c673cae
FG
443 return std::make_tuple(ok, dest, header_time);
444}
445
31f18b77
FG
446namespace rgw {
447namespace auth {
448namespace s3 {
449
450static constexpr char AWS4_HMAC_SHA256_STR[] = "AWS4-HMAC-SHA256";
224ce89b 451static constexpr char AWS4_HMAC_SHA256_PAYLOAD_STR[] = "AWS4-HMAC-SHA256-PAYLOAD";
31f18b77
FG
452
453static constexpr char AWS4_EMPTY_PAYLOAD_HASH[] = \
454 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
455
456static constexpr char AWS4_UNSIGNED_PAYLOAD_HASH[] = "UNSIGNED-PAYLOAD";
457
458static constexpr char AWS4_STREAMING_PAYLOAD_HASH[] = \
459 "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
460
a8e16298 461int parse_v4_credentials(const req_info& info, /* in */
f67539c2
TL
462 std::string_view& access_key_id, /* out */
463 std::string_view& credential_scope, /* out */
464 std::string_view& signedheaders, /* out */
465 std::string_view& signature, /* out */
466 std::string_view& date, /* out */
467 std::string_view& session_token, /* out */
b3b6e05e
TL
468 const bool using_qs, /* in */
469 const DoutPrefixProvider *dpp); /* in */
11fdf7f2
TL
470
471static inline bool char_needs_aws4_escaping(const char c, bool encode_slash)
472{
473 if ((c >= 'a' && c <= 'z') ||
474 (c >= 'A' && c <= 'Z') ||
475 (c >= '0' && c <= '9')) {
476 return false;
477 }
478
479 switch (c) {
480 case '-':
481 case '_':
482 case '.':
483 case '~':
484 return false;
485 }
486
487 if (c == '/' && !encode_slash)
488 return false;
489
490 return true;
491}
492
493static inline std::string aws4_uri_encode(const std::string& src, bool encode_slash)
494{
495 std::string result;
496
497 for (const std::string::value_type c : src) {
498 if (char_needs_aws4_escaping(c, encode_slash)) {
499 rgw_uri_escape_char(c, result);
500 } else {
501 result.push_back(c);
502 }
503 }
504
505 return result;
506}
507
f67539c2 508static inline std::string aws4_uri_recode(const std::string_view& src, bool encode_slash)
11fdf7f2
TL
509{
510 std::string decoded = url_decode(src);
511 return aws4_uri_encode(decoded, encode_slash);
512}
31f18b77
FG
513
514static inline std::string get_v4_canonical_uri(const req_info& info) {
515 /* The code should normalize according to RFC 3986 but S3 does NOT do path
516 * normalization that SigV4 typically does. This code follows the same
517 * approach that boto library. See auth.py:canonical_uri(...). */
518
11fdf7f2 519 std::string canonical_uri = aws4_uri_recode(info.request_uri_aws4, false);
31f18b77
FG
520
521 if (canonical_uri.empty()) {
522 canonical_uri = "/";
523 } else {
524 boost::replace_all(canonical_uri, "+", "%20");
525 }
526
527 return canonical_uri;
528}
529
11fdf7f2
TL
530static inline const string calc_v4_payload_hash(const string& payload)
531{
532 ceph::crypto::SHA256* sha256_hash = calc_hash_sha256_open_stream();
533 calc_hash_sha256_update_stream(sha256_hash, payload.c_str(), payload.length());
534 const auto payload_hash = calc_hash_sha256_close_stream(&sha256_hash);
535 return payload_hash;
536}
537
31f18b77
FG
538static inline const char* get_v4_exp_payload_hash(const req_info& info)
539{
11fdf7f2 540 /* In AWSv4 the hash of real, transferred payload IS NOT necessary to form
31f18b77
FG
541 * a Canonical Request, and thus verify a Signature. x-amz-content-sha256
542 * header lets get the information very early -- before seeing first byte
543 * of HTTP body. As a consequence, we can decouple Signature verification
544 * from payload's fingerprint check. */
545 const char *expected_request_payload_hash = \
546 info.env->get("HTTP_X_AMZ_CONTENT_SHA256");
547
548 if (!expected_request_payload_hash) {
549 /* An HTTP client MUST send x-amz-content-sha256. The single exception
550 * is the case of using the Query Parameters where "UNSIGNED-PAYLOAD"
551 * literals are used for crafting Canonical Request:
552 *
553 * You don't include a payload hash in the Canonical Request, because
554 * when you create a presigned URL, you don't know the payload content
555 * because the URL is used to upload an arbitrary payload. Instead, you
556 * use a constant string UNSIGNED-PAYLOAD. */
557 expected_request_payload_hash = AWS4_UNSIGNED_PAYLOAD_HASH;
558 }
559
560 return expected_request_payload_hash;
561}
562
563static inline bool is_v4_payload_unsigned(const char* const exp_payload_hash)
564{
565 return boost::equals(exp_payload_hash, AWS4_UNSIGNED_PAYLOAD_HASH);
566}
567
568static inline bool is_v4_payload_empty(const req_state* const s)
569{
570 /* from rfc2616 - 4.3 Message Body
571 *
572 * "The presence of a message-body in a request is signaled by the inclusion
573 * of a Content-Length or Transfer-Encoding header field in the request's
574 * message-headers." */
575 return s->content_length == 0 &&
576 s->info.env->get("HTTP_TRANSFER_ENCODING") == nullptr;
577}
578
579static inline bool is_v4_payload_streamed(const char* const exp_payload_hash)
580{
581 return boost::equals(exp_payload_hash, AWS4_STREAMING_PAYLOAD_HASH);
582}
583
584std::string get_v4_canonical_qs(const req_info& info, bool using_qs);
585
586boost::optional<std::string>
587get_v4_canonical_headers(const req_info& info,
f67539c2 588 const std::string_view& signedheaders,
31f18b77
FG
589 bool using_qs,
590 bool force_boto2_compat);
591
592extern sha256_digest_t
593get_v4_canon_req_hash(CephContext* cct,
f67539c2 594 const std::string_view& http_verb,
31f18b77
FG
595 const std::string& canonical_uri,
596 const std::string& canonical_qs,
597 const std::string& canonical_hdrs,
f67539c2 598 const std::string_view& signed_hdrs,
b3b6e05e
TL
599 const std::string_view& request_payload_hash,
600 const DoutPrefixProvider *dpp);
31f18b77
FG
601
602AWSEngine::VersionAbstractor::string_to_sign_t
603get_v4_string_to_sign(CephContext* cct,
f67539c2
TL
604 const std::string_view& algorithm,
605 const std::string_view& request_date,
606 const std::string_view& credential_scope,
b3b6e05e
TL
607 const sha256_digest_t& canonreq_hash,
608 const DoutPrefixProvider *dpp);
31f18b77
FG
609
610extern AWSEngine::VersionAbstractor::server_signature_t
f67539c2 611get_v4_signature(const std::string_view& credential_scope,
31f18b77 612 CephContext* const cct,
f67539c2 613 const std::string_view& secret_key,
b3b6e05e
TL
614 const AWSEngine::VersionAbstractor::string_to_sign_t& string_to_sign,
615 const DoutPrefixProvider *dpp);
31f18b77
FG
616
617extern AWSEngine::VersionAbstractor::server_signature_t
618get_v2_signature(CephContext*,
619 const std::string& secret_key,
620 const AWSEngine::VersionAbstractor::string_to_sign_t& string_to_sign);
31f18b77
FG
621} /* namespace s3 */
622} /* namespace auth */
623} /* namespace rgw */
7c673cae
FG
624
625#endif