]> 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)
committerTobias Urdin <tobias.urdin@binero.se>
Thu, 17 Aug 2023 11:47:34 +0000 (11:47 +0000)
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>
src/rgw/rgw_cors.h
src/rgw/rgw_op.cc
src/rgw/rgw_rest_s3.cc

index 17eaeeb82301c561c1364fd7c9cabe6e56d59ef0..c7a2ed5bd69c6d97ea3ce9efd910f817447f4554 100644 (file)
@@ -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;
+}
index 9dd18e322708be5fd58aa8b57c1cd94199faffb1..366a122eb33746884ce82bff37fceb8c0b6a19d3 100644 (file)
@@ -1431,18 +1431,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;
index 123bcbab7335e4d43cb72e227f657d0b258aa87a..b86353d368411dc450b513e48d2abc8db40fd6be 100644 (file)
@@ -5771,10 +5771,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),
@@ -6473,4 +6500,3 @@ bool rgw::auth::s3::S3AnonymousEngine::is_applicable(
 
   return route == AwsRoute::QUERY_STRING && version == AwsVersion::UNKNOWN;
 }
-