]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: handle http options CORS with v2 auth 59977/head
authorTobias Urdin <tobias.urdin@binero.com>
Wed, 25 Sep 2024 10:26:10 +0000 (12:26 +0200)
committerTobias Urdin <tobias.urdin@binero.com>
Wed, 25 Sep 2024 10:26:10 +0000 (12:26 +0200)
If we get a HTTP OPTIONS request for a presigned URL that
contains credentials we need to compute the signature
using the method given in the access-control-request-method
http header.

This is the same as performed for v4 auth in [1].

[1] https://github.com/ceph/ceph/pull/52673

Signed-off-by: Tobias Urdin <tobias.urdin@binero.com>
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_rest_client.cc
src/rgw/rgw_rest_s3.cc

index 412f4bf759a0da64efaa4b32f104c78e4de65943..4fe1e39d0a8d0d2b2fc9b117ca102f0ce39ad31a 100644 (file)
@@ -191,6 +191,7 @@ static inline void get_v2_qs_map(const req_info& info,
  * compute a request's signature
  */
 bool rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp,
+                                    RGWOpType op_type,
                                     const req_info& info,
                                     utime_t* const header_time,
                                     std::string& dest,
@@ -253,7 +254,8 @@ bool rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp,
     request_uri = info.effective_uri;
   }
 
-  rgw_create_s3_canonical_header(dpp, info.method, content_md5, content_type,
+  auto method = rgw::auth::s3::get_canonical_method(dpp, op_type, info);
+  rgw_create_s3_canonical_header(dpp, method.c_str(), content_md5, content_type,
                                  date.c_str(), meta_map, qs_map,
                                 request_uri.c_str(), sub_resources, dest);
   return true;
@@ -704,35 +706,6 @@ std::string gen_v4_canonical_qs(const req_info& info, bool is_non_s3_op)
   return canonical_qs;
 }
 
-std::string get_v4_canonical_method(const req_state* s)
-{
-  /* 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) {
-    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;
-      }
-
-      ldpp_dout(s, 10) << "canonical req method = " << cors_method
-                       << ", due to access-control-request-method header" << dendl;
-      return cors_method;
-    } else {
-      ldpp_dout(s, 1) << "invalid http options req missing "
-                      << "access-control-request-method header" << dendl;
-      throw -EINVAL;
-    }
-  }
-
-  return s->info.method;
-}
-
 boost::optional<std::string>
 get_v4_canonical_headers(const req_info& info,
                          const std::string_view& signedheaders,
@@ -1740,4 +1713,32 @@ AWSv4ComplSingle::create(const req_state* const s,
   return std::make_shared<AWSv4ComplSingle>(s);
 }
 
+std::string get_canonical_method(const DoutPrefixProvider *dpp, RGWOpType op_type, const req_info& info)
+{
+  /* 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 (op_type == RGW_OP_OPTIONS_CORS) {
+    const char *cors_method = 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(dpp, 1) << "invalid access-control-request-method header = "
+                          << cors_method << dendl;
+          throw -EINVAL;
+      }
+
+      ldpp_dout(dpp, 10) << "canonical req method = " << cors_method
+                       << ", due to access-control-request-method header" << dendl;
+      return cors_method;
+    } else {
+      ldpp_dout(dpp, 1) << "invalid http options req missing "
+                      << "access-control-request-method header" << dendl;
+      throw -EINVAL;
+    }
+  }
+
+  return info.method;
+}
 } // namespace rgw::auth::s3
index e1fe5163f025d290e7e51a5d1b5994f67be7f1ad..2f7fd2d75985c730ba7c797f86817e7f65e3289f 100644 (file)
@@ -500,16 +500,17 @@ void rgw_create_s3_canonical_header(
   const std::map<std::string, std::string>& sub_resources,
   std::string& dest_str);
 bool rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp,
+                                    RGWOpType op_type,
                                     const req_info& info,
                                     utime_t *header_time,       /* out */
                                     std::string& dest,          /* out */
                                     bool qsr);
 static inline std::tuple<bool, std::string, utime_t>
-rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp, const req_info& info, const bool qsr) {
+rgw_create_s3_canonical_header(const DoutPrefixProvider *dpp, RGWOpType op_type, const req_info& info, const bool qsr) {
   std::string dest;
   utime_t header_time;
 
-  const bool ok = rgw_create_s3_canonical_header(dpp, info, &header_time, dest, qsr);
+  const bool ok = rgw_create_s3_canonical_header(dpp, op_type, info, &header_time, dest, qsr);
   return std::make_tuple(ok, dest, header_time);
 }
 
@@ -704,8 +705,6 @@ std::string get_v4_canonical_qs(const req_info& info, bool using_qs);
 
 std::string gen_v4_canonical_qs(const req_info& info, bool is_non_s3_op);
 
-std::string get_v4_canonical_method(const req_state* s);
-
 boost::optional<std::string>
 get_v4_canonical_headers(const req_info& info,
                          const std::string_view& signedheaders,
@@ -745,6 +744,8 @@ extern AWSEngine::VersionAbstractor::server_signature_t
 get_v2_signature(CephContext*,
                  const std::string& secret_key,
                  const AWSEngine::VersionAbstractor::string_to_sign_t& string_to_sign);
+
+std::string get_canonical_method(const DoutPrefixProvider *dpp, RGWOpType op_type, const req_info& info);
 } /* namespace s3 */
 } /* namespace auth */
 } /* namespace rgw */
index 45b5e3076f494d77d0bbe76965db8124e9a8a8f5..c16064a61c2b3edae173640abbda62690da22658 100644 (file)
@@ -209,7 +209,7 @@ static int sign_request_v2(const DoutPrefixProvider *dpp, const RGWAccessKey& ke
   }
 
   string canonical_header;
-  if (!rgw_create_s3_canonical_header(dpp, info, NULL, canonical_header, false)) {
+  if (!rgw_create_s3_canonical_header(dpp, RGW_OP_UNKNOWN, info, NULL, canonical_header, false)) {
     ldpp_dout(dpp, 0) << "failed to create canonical s3 header" << dendl;
     return -EINVAL;
   }
index 4a50baf1cb20195b763828215bb9013898832a1b..3d87df040d409136eafc3857e0d5b8b1cc4c9320 100644 (file)
@@ -5845,7 +5845,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
   auto canonical_qs = rgw::auth::s3::get_v4_canonical_qs(s->info, using_qs);
 
   /* Craft canonical method. */
-  auto canonical_method = rgw::auth::s3::get_v4_canonical_method(s);
+  auto canonical_method = rgw::auth::s3::get_canonical_method(s, s->op_type, s->info);
 
   /* Craft canonical request. */
   auto canonical_req_hash = \
@@ -6109,7 +6109,7 @@ AWSGeneralAbstractor::get_auth_data_v2(const req_state* const s) const
   /* Let's canonize the HTTP headers that are covered by the AWS auth v2. */
   std::string string_to_sign;
   utime_t header_time;
-  if (! rgw_create_s3_canonical_header(s, s->info, &header_time, string_to_sign,
+  if (! rgw_create_s3_canonical_header(s, s->op_type, s->info, &header_time, string_to_sign,
         qsr)) {
     ldpp_dout(s, 10) << "failed to create the canonized auth header\n"
                    << rgw::crypt_sanitize::auth{s,string_to_sign} << dendl;