]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: have a configurable authentication order 22842/head
authorAbhishek Lekshmanan <abhishek@suse.com>
Thu, 1 Mar 2018 16:22:33 +0000 (17:22 +0100)
committerPrashant D <pdhange@redhat.com>
Wed, 4 Jul 2018 01:38:11 +0000 (21:38 -0400)
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`.

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 6c6c2175ebc270f3a6e749093a9c714ab236f8a8..545e3580cb3305388f5b6f74f0a1f95a9ad35061 100644 (file)
@@ -1316,6 +1316,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 9b9260b426752df63496c8a082b86213e7dcb362..cdead23ea41e3611efb24abcaca5f95922c4172d 100644 (file)
@@ -5200,6 +5200,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 6bcdebaf1cc2174bb04c639950e89fecd50bb14a..d3b6e44b74cbdda46c12b935a3673a192e0e2e15 100644 (file)
@@ -115,6 +115,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;
+      }
+      if (const auto kv = eng_map.find(eng);
+          kv != eng_map.end()) {
+        add_engine(ctrl_flag, kv->second);
+      }
+    }
+  }
+
+  auto parse_auth_order(CephContext* const cct)
+  {
+    std::vector <std::string> result;
+
+    const std::set <std::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](std::string_view s)
+                   { return allowed_auth.find(s) == allowed_auth.end();})){
+      return default_order;
+    }
+    return result;
+  }
+
   AWSAuthStrategy(CephContext* const cct,
                   RGWRados* const store)
     : store(store),
@@ -129,20 +165,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 {