]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/auth: handle HTTP OPTIONS with v4 auth
authorTobias Urdin <tobias.urdin@binero.se>
Mon, 7 Aug 2023 20:34:43 +0000 (20:34 +0000)
committerMykola Golub <mgolub@suse.com>
Tue, 12 Sep 2023 09:34:17 +0000 (12:34 +0300)
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 <tobias.urdin@binero.com>
(cherry picked from commit 814cae52baf04d9c3f0f3bd04b8e2daf16eb3874)

Conflicts:
src/rgw/rgw_cors.h (trivial)
src/rgw/rgw_op.cc (different signature for validate_cors_rule_method)
src/rgw/rgw_rest_s3.cc (trivial)

src/rgw/rgw_cors.h
src/rgw/rgw_op.cc
src/rgw/rgw_rest_s3.cc

index 6679900953b6d9b376d829272fe32c2c88e0e572..af0ed3c7910d9ba406c14abf2d27177f34ccb356 100644 (file)
@@ -133,4 +133,17 @@ 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;
+}
+
 #endif /*CEPH_RGW_CORS_H*/
index e2d74d9cedd7257534e3e250dd4883f25e48578f..28c813690b589dfcd1c6e9764ee80b680263dcc2 100644 (file)
@@ -1466,18 +1466,12 @@ int RGWOp::init_quota()
 }
 
 static bool validate_cors_rule_method(RGWCORSRule *rule, const char *req_meth) {
-  uint8_t flags = 0;
-
   if (!req_meth) {
     dout(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) {
     dout(10) << "Method " << req_meth << " is supported" << dendl;
index 3069e9b5c38bd6f36fc41ed41879d40ca311b68e..7be866ba291a2932d54769722809b45b1b213e5b 100644 (file)
@@ -5291,10 +5291,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),