]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: have a configurable authentication order 23501/head
authorAbhishek Lekshmanan <abhishek@suse.com>
Thu, 1 Mar 2018 16:22:33 +0000 (17:22 +0100)
committerAbhishek Lekshmanan <abhishek@suse.com>
Thu, 9 Aug 2018 08:02:21 +0000 (10:02 +0200)
This implements a configurable authentication order, currently used only for s3
authentication and only supporting external & local authentication, though there
is potential for more finegrained control by allowing for a map of various
engines and the control strategy (required vs sufficient vs fallback)

The current implementation just focuses on setting control fallback if the
engine is the last in the order (and hence the stack) and just sets sufficient to
every other element, so that errors from the last sufficient engine is returned.

The configuration option is rgw_s3_auth_order which takes a comma/space seperated
list of authentication engines where currently we support the keywords `external`
and `local`.

Luminous specific changes:
std::string_view -> boost::string_view
auto function return -> return type std::vector<std::string>
if initializer list dropped

Fixes: http://tracker.ceph.com/issues/23089
Signed-off-by: Abhishek Lekshmanan <abhishek@suse.com>
(cherry picked from commit 9c7fc682ca23259037115db3437c2bc9dd91fa22)

src/common/legacy_config_opts.h
src/common/options.cc
src/rgw/rgw_auth_s3.h

index 69bfcd7dee369501397f0d0c408068ab0b1040b5..38b36a60cc88eec35879c7a0f094acdd5003b12f 100644 (file)
@@ -1375,6 +1375,7 @@ OPTION(rgw_cross_domain_policy, OPT_STR)
 OPTION(rgw_healthcheck_disabling_path, OPT_STR) // path that existence causes the healthcheck to respond 503
 OPTION(rgw_s3_auth_use_rados, OPT_BOOL)  // should we try to use the internal credentials for s3?
 OPTION(rgw_s3_auth_use_keystone, OPT_BOOL)  // should we try to use keystone for s3?
+OPTION(rgw_s3_auth_order, OPT_STR) // s3 authentication order to try
 OPTION(rgw_barbican_url, OPT_STR)  // url for barbican server
 
 /* OpenLDAP-style LDAP parameter strings */
index 5d1f1fb9e3339515bf3a087b37cc4d1eae71c168..1ed027c9bebd6938ef37b37eeb1f758bdcc50d00 100644 (file)
@@ -4709,6 +4709,15 @@ std::vector<Option> get_rgw_options() {
     .set_default(false)
     .set_description("Should S3 authentication use Keystone."),
 
+    Option("rgw_s3_auth_order", Option::TYPE_STR, Option::LEVEL_ADVANCED)
+     .set_default("external, local")
+     .set_description("Authentication strategy order to use for s3 authentication")
+     .set_long_description(
+         "Order of authentication strategies to try for s3 authentication, the allowed "
+          "options are a comma separated list of engines external, local. The "
+          "default order is to try all the externally configured engines before "
+          "attempting local rados based authentication"),
+
     Option("rgw_barbican_url", Option::TYPE_STR, Option::LEVEL_ADVANCED)
     .set_default("")
     .set_description("URL to barbican server."),
index 2a875d4798f021d2251d9087c2502b1379d70b94..6f860a72a2e1fc0d98e522fd6b5896d108432671 100644 (file)
@@ -119,6 +119,42 @@ class AWSAuthStrategy : public rgw::auth::Strategy,
   }
 
 public:
+  using engine_map_t = std::map <std::string, std::reference_wrapper<const Engine>>;
+  void add_engines(const std::vector <std::string>& auth_order,
+                  engine_map_t eng_map)
+  {
+    auto ctrl_flag = Control::SUFFICIENT;
+    for (const auto &eng : auth_order) {
+      // fallback to the last engine, in case of multiple engines, since ctrl
+      // flag is sufficient for others, error from earlier engine is returned
+      if (&eng == &auth_order.back() && eng_map.size() > 1) {
+        ctrl_flag = Control::FALLBACK;
+      }
+      const auto kv = eng_map.find(eng);
+      if (kv != eng_map.end()) {
+        add_engine(ctrl_flag, kv->second);
+      }
+    }
+  }
+
+  std::vector<std::string> parse_auth_order(CephContext* const cct)
+  {
+    std::vector <std::string> result;
+
+    const std::set <boost::string_view> allowed_auth = { "external", "local" };
+    std::vector <std::string> default_order = { "external", "local"};
+    // supplied strings may contain a space, so let's bypass that
+    boost::split(result, cct->_conf->rgw_s3_auth_order,
+                boost::is_any_of(", "), boost::token_compress_on);
+
+    if (std::any_of(result.begin(), result.end(),
+                   [allowed_auth](boost::string_view s)
+                   { return allowed_auth.find(s) == allowed_auth.end();})){
+      return default_order;
+    }
+    return result;
+  }
+
   AWSAuthStrategy(CephContext* const cct,
                   rgw::auth::ImplicitTenants& implicit_tenant_context,
                   RGWRados* const store)
@@ -134,20 +170,17 @@ public:
       add_engine(Control::SUFFICIENT, anonymous_engine);
     }
 
+    auto auth_order = parse_auth_order(cct);
+    engine_map_t engine_map;
     /* The external auth. */
-    Control local_engine_mode;
     if (! external_engines.is_empty()) {
-      add_engine(Control::SUFFICIENT, external_engines);
-
-      local_engine_mode = Control::FALLBACK;
-    } else {
-      local_engine_mode = Control::SUFFICIENT;
+      engine_map.insert(std::make_pair("external", std::cref(external_engines)));
     }
-
     /* The local auth. */
     if (cct->_conf->rgw_s3_auth_use_rados) {
-      add_engine(local_engine_mode, local_engine);
+      engine_map.insert(std::make_pair("local", std::cref(local_engine)));
     }
+    add_engines(auth_order, engine_map);
   }
 
   const char* get_name() const noexcept override {