]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: RGWPostObj_ObjStore_S3 doesn't instantiate auth strategy for each request anymore.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Tue, 7 Feb 2017 14:11:19 +0000 (15:11 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 21:45:27 +0000 (22:45 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth_s3.h
src/rgw/rgw_common.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index a50229cb3670b709f0af960678615a986b8d5816..f52cc7752da725b5dc50a1bdc39236bdb03a157a 100644 (file)
@@ -71,12 +71,18 @@ public:
 };
 
 
+template <class ExtractorT>
 class AWSv2AuthStrategy : public rgw::auth::Strategy,
                           public rgw::auth::LocalApplier::Factory {
   typedef rgw::auth::IdentityApplier::aplptr_t aplptr_t;
+
+  static_assert(std::is_base_of<rgw::auth::s3::Version2ndEngine::Extractor,
+                                ExtractorT>::value,
+                "ExtractorT must be a subclass of rgw::auth::s3::ExtractorT");
+
   RGWRados* const store;
+  ExtractorT extractor;
 
-  rgw::auth::s3::RGWS3V2Extractor extractor;
   ExternalAuthStrategy external_engines;
   LocalVersion2ndEngine local_engine;
 
@@ -99,23 +105,9 @@ public:
       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);
-    }
-  }
 
-  /* FIXME(rzarzynski): hack for S3's browsers upload. */
-  AWSv2AuthStrategy(CephContext* const cct,
-                    RGWRados* const store,
-                    Version2ndEngine::Extractor* const external_extractor)
-    : store(store),
-      extractor(cct),
-      external_engines(cct, store, external_extractor),
-      local_engine(cct, store, *external_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);
+      add_engine(Control::FALLBACK, local_engine);
     }
   }
 
index 820efc2307d39fd92e2165c63bee7108fdd100a0..e01858e9764b6e0f90db372fb2914507fe76ddd1 100644 (file)
@@ -1334,10 +1334,16 @@ struct req_state;
 
 class RGWEnv;
 
+/* Namespaced forward declarations. */
 namespace rgw {
-namespace io {
-class BasicClient;
-}
+  namespace auth {
+    namespace s3 {
+      class RGWGetPolicyV2Extractor;
+    }
+  }
+  namespace io {
+    class BasicClient;
+  }
 }
 
 struct req_info {
@@ -1735,6 +1741,21 @@ struct req_state {
     std::unique_ptr<rgw::auth::Identity> identity;
 
     std::unique_ptr<rgw::auth::Completer> completer;
+
+    /* A container for credentials of the S3's browser upload. It's necessary
+     * because: 1) the ::authenticate() method of auth engines and strategies
+     * take req_state only; 2) auth strategies live much longer than RGWOps -
+     * there is no way to pass additional data dependencies through ctors. */
+    class {
+      /* Writer. */
+      friend class RGWPostObj_ObjStore_S3;
+      /* Reader. */
+      friend class rgw::auth::s3::RGWGetPolicyV2Extractor;
+
+      std::string access_key;
+      std::string signature;
+      ceph::bufferlist encoded_policy;
+    } s3_postobj_creds;
   } auth;
 
   std::unique_ptr<RGWAccessControlPolicy> user_acl;
index 63bd0b99cdda7f6d22f9f17ff148402eee64d234..5d18249e2f867b216def429dbc0a4923dc4904bf 100644 (file)
@@ -1798,39 +1798,28 @@ int RGWPostObj_ObjStore_S3::get_params()
   return 0;
 }
 
-static std::string to_string(ceph::bufferlist& bl)
-{
-  return std::string(bl.c_str(),
-                     static_cast<std::string::size_type>(bl.length()));
-}
-
 int RGWPostObj_ObjStore_S3::get_policy()
 {
-  bufferlist encoded_policy;
-
-  if (part_bl("policy", &encoded_policy)) {
+  if (part_bl("policy", &s->auth.s3_postobj_creds.encoded_policy)) {
 
     // check that the signature matches the encoded policy
-    string s3_access_key;
-    if (!part_str("AWSAccessKeyId", &s3_access_key)) {
+    if (! part_str("AWSAccessKeyId", &s->auth.s3_postobj_creds.access_key)) {
       ldout(s->cct, 0) << "No S3 access key found!" << dendl;
       err_msg = "Missing access key";
       return -EINVAL;
     }
     string received_signature_str;
-    if (!part_str("signature", &received_signature_str)) {
+    if (! part_str("signature", &s->auth.s3_postobj_creds.signature)) {
       ldout(s->cct, 0) << "No signature found!" << dendl;
       err_msg = "Missing signature";
       return -EINVAL;
     }
 
-    rgw::auth::s3::RGWGetPolicyV2Extractor extr(s3_access_key,
-                                                received_signature_str,
-                                                to_string(encoded_policy));
-    /* FIXME: this is a makeshift solution. The browser upload authenication will be
+    /* FIXME: this is a makeshift solution. The browser upload authentication 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, &extr);
+     * method. */
+    static const rgw::auth::s3::AWSv2AuthStrategy<
+                   rgw::auth::s3::RGWGetPolicyV2Extractor> strategy(g_ceph_context, store);
     try {
       auto result = strategy.authenticate(s);
       if (result.get_status() != decltype(result)::Status::GRANTED) {
@@ -1859,7 +1848,7 @@ int RGWPostObj_ObjStore_S3::get_policy()
 
     ceph::bufferlist decoded_policy;
     try {
-      decoded_policy.decode_base64(encoded_policy);
+      decoded_policy.decode_base64(s->auth.s3_postobj_creds.encoded_policy);
     } catch (buffer::error& err) {
       ldout(s->cct, 0) << "failed to decode_base64 policy" << dendl;
       err_msg = "Could not decode policy";
@@ -3896,7 +3885,7 @@ int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s)
 {
   /* 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);
+  static const rgw::auth::s3::AWSv2AuthStrategy<rgw::auth::s3::RGWS3V2Extractor> strategy(g_ceph_context, store);
   try {
     auto result = strategy.authenticate(s);
     if (result.get_status() != decltype(result)::Status::GRANTED) {
index 6ca8c899a6d3b78258b65247c1c4bbc6afee794b..dcd9311d18c464ab628162bd7409cca8c3d501eb 100644 (file)
@@ -685,25 +685,22 @@ public:
 
 
 class RGWGetPolicyV2Extractor : public Version2ndEngine::Extractor {
-private:
-  std::string access_key_id;
-  std::string signature;
-  std::string string_to_sign;
+  static std::string to_string(ceph::bufferlist bl) {
+    return std::string(bl.c_str(),
+                       static_cast<std::string::size_type>(bl.length()));
+  }
 
 public:
-  RGWGetPolicyV2Extractor(std::string access_key_id,
-                          std::string signature,
-                          std::string string_to_sign)
-    : access_key_id(std::move(access_key_id)),
-      signature(std::move(signature)),
-      string_to_sign(std::move(string_to_sign)) {
+  RGWGetPolicyV2Extractor(CephContext*) {
   }
 
   std::tuple<access_key_id_t,
              signature_t,
              string_to_sign_t>
   get_auth_data(const req_state* s) const override {
-    return std::make_tuple(access_key_id, signature, string_to_sign);
+    return std::make_tuple(s->auth.s3_postobj_creds.access_key,
+                           s->auth.s3_postobj_creds.signature,
+                           to_string(s->auth.s3_postobj_creds.encoded_policy));
   }
 };