From: Tobias Urdin Date: Mon, 7 Aug 2023 20:34:43 +0000 (+0000) Subject: rgw/auth: handle HTTP OPTIONS with v4 auth X-Git-Tag: v18.2.1~287^2~1 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=d4fd9f7b000faefe188946c148979b7e14f7c158;p=ceph-ci.git rgw/auth: handle HTTP OPTIONS with v4 auth This adds code to properly verify the signature for HTTP OPTIONS calls that is preflight CORS requests passing the expected method in the access-control-request-method header. Fixes: https://tracker.ceph.com/issues/62033 Signed-off-by: Tobias Urdin (cherry picked from commit 814cae52baf04d9c3f0f3bd04b8e2daf16eb3874) --- diff --git a/src/rgw/rgw_cors.h b/src/rgw/rgw_cors.h index 17eaeeb8230..c7a2ed5bd69 100644 --- a/src/rgw/rgw_cors.h +++ b/src/rgw/rgw_cors.h @@ -132,3 +132,15 @@ static inline int validate_name_string(std::string_view o) { return -1; return 0; } + +static inline uint8_t get_cors_method_flags(const char *req_meth) { + uint8_t flags = 0; + + if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET; + else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST; + else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT; + else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE; + else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD; + + return flags; +} diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index 79d7e939694..df09223ca90 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -1430,18 +1430,12 @@ int RGWOp::init_quota() } static bool validate_cors_rule_method(const DoutPrefixProvider *dpp, RGWCORSRule *rule, const char *req_meth) { - uint8_t flags = 0; - if (!req_meth) { ldpp_dout(dpp, 5) << "req_meth is null" << dendl; return false; } - if (strcmp(req_meth, "GET") == 0) flags = RGW_CORS_GET; - else if (strcmp(req_meth, "POST") == 0) flags = RGW_CORS_POST; - else if (strcmp(req_meth, "PUT") == 0) flags = RGW_CORS_PUT; - else if (strcmp(req_meth, "DELETE") == 0) flags = RGW_CORS_DELETE; - else if (strcmp(req_meth, "HEAD") == 0) flags = RGW_CORS_HEAD; + uint8_t flags = get_cors_method_flags(req_meth); if (rule->get_allowed_methods() & flags) { ldpp_dout(dpp, 10) << "Method " << req_meth << " is supported" << dendl; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index efd23a3e17e..9b3e6faf904 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -5767,10 +5767,37 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s, /* Craft canonical query string. std::moving later so non-const here. */ auto canonical_qs = rgw::auth::s3::get_v4_canonical_qs(s->info, using_qs); + const char *req_meth = s->info.method; + + /* If this is a OPTIONS request we need to compute the v4 signature for the + * intended HTTP method and not the OPTIONS request itself. */ + if (s->op_type == RGW_OP_OPTIONS_CORS) { + /* Validate signature for CORS header if set otherwise use HTTP request method. */ + const char *cors_method = s->info.env->get("HTTP_ACCESS_CONTROL_REQUEST_METHOD"); + + if (cors_method) { + /* Validate request method passed in access-control-request-method is valid. */ + auto cors_flags = get_cors_method_flags(cors_method); + if (!cors_flags) { + ldpp_dout(s, 1) << "invalid access-control-request-method header = " + << cors_method << dendl; + throw -EINVAL; + } + + req_meth = cors_method; + ldpp_dout(s, 10) << "setting canonical req method = " << cors_method + << ", due to access-control-request-method header" << dendl; + } else { + ldpp_dout(s, 1) << "invalid http options req missing " + << "access-control-request-method header" << dendl; + throw -EINVAL; + } + } + /* Craft canonical request. */ auto canonical_req_hash = \ rgw::auth::s3::get_v4_canon_req_hash(s->cct, - s->info.method, + req_meth, std::move(canonical_uri), std::move(canonical_qs), std::move(*canonical_headers), @@ -6468,4 +6495,3 @@ bool rgw::auth::s3::S3AnonymousEngine::is_applicable( return route == AwsRoute::QUERY_STRING && version == AwsVersion::UNKNOWN; } -