]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: aws4: add rgw_s3_auth_aws4_force_boto2_compat conf option 10160/head
authorJavier M. Mellid <jmunhoz@igalia.com>
Mon, 1 Aug 2016 19:00:28 +0000 (21:00 +0200)
committerJavier M. Mellid <jmunhoz@igalia.com>
Thu, 15 Dec 2016 23:59:49 +0000 (00:59 +0100)
Runtime bugfix to handle presigned urls computed with canonical requests using
the port number once.

Boto2 computes canonical requests using the port number twice although it
should be used once only. This behaviour is a bug supported by AWS S3. Boto2 is
used in RGW S3 as reference implementation.

The client-side tools not supporting this boto2 bug will fail although they
should work too.

In order to support both presigned url implementations this patch adds a config
option to compute a second signature. With this option disabled, the code will
compute two signatures when the first signature is not valid. The aws4 auth
succeed if some of the two signatures is valid.

The config option rgw_s3_auth_aws4_force_boto2_compat, is enabled by default so
one signature, working with boto2, is computed only.

Fixes: http://tracker.ceph.com/issues/16463
Signed-off-by: Javier M. Mellid <jmunhoz@igalia.com>
src/common/config_opts.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index 41a109875df0b6ba9613f66fdf38e33098aebfaa..e8ef9b3b8aae5c7b2d6a79a62bdd87254f9dbdfd 100644 (file)
@@ -1331,6 +1331,7 @@ OPTION(rgw_keystone_verify_ssl, OPT_BOOL, true) // should we try to verify keyst
 OPTION(rgw_keystone_implicit_tenants, OPT_BOOL, false)  // create new users in their own tenants of the same name
 OPTION(rgw_s3_auth_use_rados, OPT_BOOL, true)  // should we try to use the internal credentials for s3?
 OPTION(rgw_s3_auth_use_keystone, OPT_BOOL, false)  // should we try to use keystone for s3?
+OPTION(rgw_s3_auth_aws4_force_boto2_compat, OPT_BOOL, true) // force aws4 auth boto2 compatibility
 
 /* OpenLDAP-style LDAP parameter strings */
 /* rgw_ldap_uri  space-separated list of LDAP servers in URI format */
index dfd8ae1dd1fa7dade38cab2e7accab18bbedc423..e01d61145508bcaa437fdd4328967f98666e70cc 100644 (file)
@@ -3307,7 +3307,14 @@ int RGW_Auth_S3::authorize(RGWRados *store, struct req_state *s)
       if (algorithm != "AWS4-HMAC-SHA256") {
         return -EPERM;
       }
-      return authorize_v4(store, s);
+      /* compute first aws4 signature (stick to the boto2 implementation) */
+      int err = authorize_v4(store, s);
+      if ((err==-ERR_SIGNATURE_NO_MATCH) && !store->ctx()->_conf->rgw_s3_auth_aws4_force_boto2_compat) {
+        /* compute second aws4 signature (no bugs supported) */
+        ldout(s->cct, 10) << "computing second aws4 signature..." << dendl;
+        return authorize_v4(store, s, false);
+      }
+      return err;
     }
 
     /* AWS2 */
@@ -3461,7 +3468,7 @@ static std::array<string, 3> aws4_presigned_required_keys = { "Credential", "Sig
 /*
  * handle v4 signatures (rados auth only)
  */
-int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s)
+int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s, bool force_boto2_compat /* = true */)
 {
   string::size_type pos;
   bool using_qs;
@@ -3736,7 +3743,7 @@ int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s)
       }
     }
     string token_value = string(t);
-    if (using_qs && (token == "host")) {
+    if (force_boto2_compat && using_qs && (token == "host")) {
       if (!port.empty() && port != "80" && port != "0") {
         token_value = token_value + ":" + port;
       } else if (!secure_port.empty() && secure_port != "443") {
index c48b2eb1f6987fd06a768a5421a4564376870a38..b7f49306d56174940cf6bf254cb61aac2b01be5b 100644 (file)
@@ -449,7 +449,7 @@ private:
   static rgw::LDAPHelper* ldh;
 
   static int authorize_v2(RGWRados *store, struct req_state *s);
-  static int authorize_v4(RGWRados *store, struct req_state *s);
+  static int authorize_v4(RGWRados *store, struct req_state *s, bool force_boto2_compat = true);
   static int authorize_v4_complete(RGWRados *store, struct req_state *s,
                                  const string& request_payload,
                                  bool unsigned_payload);