]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add rgw::auth::s3::AWSv2AuthStrategy and switch the S3 auth to it.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Wed, 11 Jan 2017 15:26:53 +0000 (16:26 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 15:55:27 +0000 (16:55 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth_s3.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index 7e5205cf5544b9144f136e477af6d0836bb4cbf1..99f5d015b5f515e0a49ba58d3d5851b78977df97 100644 (file)
@@ -11,6 +11,7 @@
 #include "rgw_rest_s3.h"
 
 #include "rgw_auth.h"
+#include "rgw_auth_filters.h"
 #include "rgw_auth_keystone.h"
 
 
@@ -35,8 +36,10 @@ class ExternalAuthStrategy : public rgw::auth::Strategy,
                              rgw::auth::RemoteApplier::acl_strategy_t&& acl_alg,
                              const rgw::auth::RemoteApplier::AuthInfo info
                             ) const override {
-    return aplptr_t(
-      new rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info));
+    auto apl = rgw::auth::add_sysreq(cct, store, s,
+      rgw::auth::RemoteApplier(cct, store, std::move(acl_alg), info));
+    /* TODO(rzarzynski): replace with static_ptr. */
+    return aplptr_t(new decltype(apl)(std::move(apl)));
   }
 
 public:
@@ -66,6 +69,45 @@ public:
     return "rgw::auth::s3::AWSv2ExternalAuthStrategy";
   }
 };
+
+
+class AWSv2AuthStrategy : public rgw::auth::Strategy,
+                          public rgw::auth::LocalApplier::Factory {
+  typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
+  RGWRados* const store;
+
+  rgw::auth::s3::RGWS3V2Extractor extractor;
+  ExternalAuthStrategy external_engines;
+  LocalVersion2ndEngine local_engine;
+
+  aplptr_t create_apl_local(CephContext* const cct,
+                            const req_state* const s,
+                            const RGWUserInfo& user_info,
+                            const std::string& subuser) const override {
+    auto apl = rgw::auth::add_sysreq(cct, store, s,
+      rgw::auth::LocalApplier(cct, user_info, subuser));
+    /* TODO(rzarzynski): replace with static_ptr. */
+    return aplptr_t(new decltype(apl)(std::move(apl)));
+  }
+
+public:
+  AWSv2AuthStrategy(CephContext* const cct,
+                    RGWRados* const store)
+    : store(store),
+      external_engines(cct, store, &extractor),
+      local_engine(cct, store, extractor,
+                   static_cast<rgw::auth::LocalApplier::Factory*>(this)) {
+    add_engine(Control::SUFFICIENT, external_engines);
+    if (cct->_conf->rgw_s3_auth_use_rados) {
+      add_engine(Control::SUFFICIENT, local_engine);
+    }
+  }
+
+  const char* get_name() const noexcept override {
+    return "rgw::auth::s3::AWSv2AuthStrategy";
+  }
+};
+
 } /* namespace s3 */
 } /* namespace auth */
 } /* namespace rgw */
index fbd988eba923120c9d3d970dc5f8de13b0bfd2ed..b86f36a0b49a67c17ab28cbe61f67bbe642c2ff6 100644 (file)
@@ -1817,71 +1817,33 @@ int RGWPostObj_ObjStore_S3::get_policy()
       err_msg = "Missing signature";
       return -EINVAL;
     }
-    RGWUserInfo user_info;
-
-    op_ret = rgw_get_user_info_by_access_key(store, s3_access_key, user_info);
-    if (op_ret < 0) {
-      // try external authenticators
-      rgw::auth::s3::RGWGetPolicyV2Extractor extr(s3_access_key, received_signature_str);
-      /* FIXME: this is a makeshift solution. The browser upload authenication will be
-       * handled by an instance of rgw::auth::Completer spawned in Handler's authorize()
-       * method. Thus creating a strategy per request won't be necessary. */
-      rgw::auth::s3::ExternalAuthStrategy strategy(s->cct, store, &extr);
-      try {
-        auto result = strategy.authenticate(s);
-        auto& applier = result.first;
-        if (! applier) {
-          return -EACCES;
-        }
 
-        try {
-          applier->load_acct_info(user_info);
-          s->perm_mask = applier->get_perm_mask();
-          applier->modify_request_state(s);
-          s->auth.identity = std::move(applier);
-        } catch (int err) {
-          return -EACCES;
-        }
-      } catch (int err) {
+    rgw::auth::s3::RGWGetPolicyV2Extractor extr(s3_access_key, received_signature_str);
+    /* FIXME: this is a makeshift solution. The browser upload authenication will be
+     * handled by an instance of rgw::auth::Completer spawned in Handler's authorize()
+     * method. Thus creating a strategy per request won't be necessary. */
+    const rgw::auth::s3::AWSv2AuthStrategy strategy(g_ceph_context, store);
+    try {
+      auto result = strategy.authenticate(s);
+      auto& applier = result.first;
+      if (! applier) {
         return -EACCES;
       }
-    } else {
-      map<string, RGWAccessKey> access_keys  = user_info.access_keys;
-
-      map<string, RGWAccessKey>::const_iterator iter =
-       access_keys.find(s3_access_key);
-      // We know the key must exist, since the user was returned by
-      // rgw_get_user_info_by_access_key, but it doesn't hurt to check!
-      if (iter == access_keys.end()) {
-       ldout(s->cct, 0) << "Secret key lookup failed!" << dendl;
-       err_msg = "No secret key for matching access key";
-       return -EACCES;
-      }
-      string s3_secret_key = (iter->second).key;
-
-      char expected_signature_char[CEPH_CRYPTO_HMACSHA1_DIGESTSIZE];
-
-      calc_hmac_sha1(s3_secret_key.c_str(), s3_secret_key.size(),
-                    encoded_policy.c_str(), encoded_policy.length(),
-                    expected_signature_char);
-      bufferlist expected_signature_hmac_raw;
-      bufferlist expected_signature_hmac_encoded;
-      expected_signature_hmac_raw.append(expected_signature_char,
-                                        CEPH_CRYPTO_HMACSHA1_DIGESTSIZE);
-      expected_signature_hmac_raw.encode_base64(
-       expected_signature_hmac_encoded);
-      expected_signature_hmac_encoded.append((char)0); /* null terminate */
-
-      if (received_signature_str.compare(
-           expected_signature_hmac_encoded.c_str()) != 0) {
-       ldout(s->cct, 0) << "Signature verification failed!" << dendl;
-       ldout(s->cct, 0) << "received: " << received_signature_str.c_str()
-                        << dendl;
-       ldout(s->cct, 0) << "expected: "
-                        << expected_signature_hmac_encoded.c_str() << dendl;
-       err_msg = "Bad access key / signature";
-       return -EACCES;
+
+      try {
+        applier->load_acct_info(*s->user);
+        s->perm_mask = applier->get_perm_mask();
+        applier->modify_request_state(s);
+        s->auth.identity = std::move(applier);
+
+        s->owner.set_id(s->user->user_id);
+        s->owner.set_name(s->user->display_name);
+        /* OK, fall through. */
+      } catch (int err) {
+        return -EACCES;
       }
+    } catch (int err) {
+      return -EACCES;
     }
 
     ldout(s->cct, 0) << "Successful Signature Verification!" << dendl;
@@ -1920,14 +1882,6 @@ int RGWPostObj_ObjStore_S3::get_policy()
       return r;
     }
 
-    // deep copy
-    *(s->user) = user_info;
-    s->owner.set_id(user_info.user_id);
-    s->owner.set_name(user_info.display_name);
-
-    /* FIXME: remove this after switching S3 to the new authentication
-     * infrastructure. */
-    s->auth.identity = rgw::auth::transform_old_authinfo(s);
   } else {
     ldout(s->cct, 0) << "No attached policy found!" << dendl;
   }
@@ -3954,88 +3908,37 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
     auth_sign = auth_str.substr(pos + 1);
   }
 
-  rgw::auth::s3::S3AuthFactory aplfact(store);
-  rgw::auth::s3::RGWS3V2Extractor extr;
-
-  /* TODO(rzarzynski): the final strategy will be a part of Handler - exactly
-   * like in the case of Swift API. */
-  static rgw::auth::s3::ExternalAuthStrategy strategy(g_ceph_context,
-                                                      store, &extr);
-  /* try external auth first */
-  int external_auth_result = -ERR_INVALID_ACCESS_KEY;
+  /* TODO(rzarzynski): this will be moved to the S3 handlers -- in exactly
+   * way like we currently have in the case of Swift API. */
+  static const rgw::auth::s3::AWSv2AuthStrategy strategy(g_ceph_context, store);
   try {
     auto result = strategy.authenticate(s);
     auto& applier = result.first;
     if (! applier) {
-      return -EACCES;
+      return -EPERM;
     }
-
     try {
       applier->load_acct_info(*s->user);
       s->perm_mask = applier->get_perm_mask();
       applier->modify_request_state(s);
       s->auth.identity = std::move(applier);
-    } catch (int err) {
-      ldout(s->cct, 5) << "applier threw err=" << err << dendl;
-      external_auth_result = err;
-    }
-  } catch (int err) {
-    ldout(s->cct, 5) << "external auth strategy threw err=" << err << dendl;
-    external_auth_result = err;
-  }
 
-  /* now try rados backend, but only if externals did not succeed */
-  /* TODO(rzarzynski): aggregate the externals with the local engine in
-   * as a final AuthStrategy for S3V2. */
-  if (external_auth_result < 0) {
-      rgw::auth::s3::LocalVersion2ndEngine localauth(s->cct, store, extr, &aplfact);
+      /* Populate the owner info. */
+      s->owner.set_id(s->user->user_id);
+      s->owner.set_name(s->user->display_name);
 
-      if (! s->cct->_conf->rgw_s3_auth_use_rados) {
-        return external_auth_result;
-      }
-      try {
-        auto result = localauth.authenticate(s);
-        auto& applier = result.first;
-        if (! applier) {
-          return external_auth_result;
-        }
-        try {
-          applier->load_acct_info(*s->user);
-          s->perm_mask = applier->get_perm_mask();
-          applier->modify_request_state(s);
-          s->auth.identity = std::move(applier);
-        } catch (int err) {
-          ldout(s->cct, 5) << "applier threw err=" << err << dendl;
-          return err;
-        }
-      } catch (int err) {
-          ldout(s->cct, 5) << "local auth engine threw err=" << err << dendl;
-          return err;
-      }
-    if (s->user->system) {
-      s->system_request = true;
-      dout(20) << "system request" << dendl;
-      s->info.args.set_system();
-      string effective_uid = s->info.args.get(RGW_SYS_PARAM_PREFIX "uid");
-      RGWUserInfo effective_user;
-      if (!effective_uid.empty()) {
-        rgw_user euid(effective_uid);
-        int ret = rgw_get_user_info_by_uid(store, euid, effective_user);
-        if (ret < 0) {
-          ldout(s->cct, 0) << "User lookup failed!" << dendl;
-          return -EACCES;
-        }
-        *(s->user) = effective_user;
-      }
+      /* Success - not throwed. */
+      return 0;
+    } catch (const int err) {
+      ldout(s->cct, 5) << "applier threw err=" << err << dendl;
+      return err;
     }
+  } catch (const int err) {
+    ldout(s->cct, 5) << "local auth engine threw err=" << err << dendl;
+    return err;
+  }
 
-  } /* if external_auth_result < 0 */
-
-  // populate the owner info
-  s->owner.set_id(s->user->user_id);
-  s->owner.set_name(s->user->display_name);
-
-  return  0;
+  return -ERR_SIGNATURE_NO_MATCH;
 }
 
 int RGWHandler_Auth_S3::init(RGWRados *store, struct req_state *state,
index de2023c2a83a66974da2a0a1e57080338a5a0b6a..1ba7242be846652ef4ad51c317285fa57d93234b 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "rgw_auth.h"
 #include "rgw_auth_decoimpl.h"
+#include "rgw_auth_filters.h"
 
 #define RGW_AUTH_GRACE_MINS 15