]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: Keystone implementation can support multiple instances now.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Mon, 7 Nov 2016 11:09:45 +0000 (12:09 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 15:54:32 +0000 (16:54 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth.cc
src/rgw/rgw_json_enc.cc
src/rgw/rgw_keystone.cc
src/rgw/rgw_keystone.h
src/rgw/rgw_rest_s3.cc

index 060b10c12358680bb9068a237542de1b9a0da099..8b189d13aff2d47199958dc09254ee11d3f4b185 100644 (file)
@@ -297,7 +297,8 @@ RGWKeystoneAuthEngine::decode_pki_token(const std::string& token) const
   }
 
   rgw::keystone::TokenEnvelope token_body;
-  ret = token_body.parse(cct, token, token_body_bl);
+  ret = token_body.parse(cct, token, token_body_bl,
+                         rgw::keystone::CephCtxConfig::get_instance().get_api_version());
   if (ret < 0) {
     throw ret;
   }
@@ -314,12 +315,13 @@ RGWKeystoneAuthEngine::get_from_keystone(const std::string& token) const
   bufferlist token_body_bl;
   RGWValidateKeystoneToken validate(cct, &token_body_bl);
 
-  std::string url;
-  if (rgw::keystone::Service::get_keystone_url(cct, url) < 0) {
+  std::string url
+    = rgw::keystone::CephCtxConfig::get_instance().get_endpoint_url();
+  if (url.empty()) {
     throw -EINVAL;
   }
 
-  const auto keystone_version = rgw::keystone::Service::get_api_version();
+  const auto keystone_version = rgw::keystone::CephCtxConfig::get_instance().get_api_version();
   if (keystone_version == rgw::keystone::ApiVersion::VER_2) {
     url.append("v2.0/tokens/" + token);
   } else if (keystone_version == rgw::keystone::ApiVersion::VER_3) {
@@ -328,7 +330,11 @@ RGWKeystoneAuthEngine::get_from_keystone(const std::string& token) const
   }
 
   std::string admin_token;
-  if (rgw::keystone::Service::get_keystone_admin_token(cct, admin_token) < 0) {
+  if (rgw::keystone::Service::get_admin_token(
+          cct,
+          rgw::keystone::TokenCache::get_instance<rgw::keystone::CephCtxConfig>(),
+          rgw::keystone::CephCtxConfig::get_instance(),
+          admin_token) < 0) {
     throw -EINVAL;
   }
 
@@ -359,7 +365,7 @@ RGWKeystoneAuthEngine::get_from_keystone(const std::string& token) const
   }
 
   rgw::keystone::TokenEnvelope token_body;
-  ret = token_body.parse(cct, token, token_body_bl);
+  ret = token_body.parse(cct, token, token_body_bl, keystone_version);
   if (ret < 0) {
     throw ret;
   }
@@ -465,7 +471,7 @@ RGWAuthApplier::aplptr_t RGWKeystoneAuthEngine::authenticate() const
   ldout(cct, 20) << "token_id=" << token_id << dendl;
 
   /* Check cache first. */
-  if (rgw::keystone::TokenCache::get_instance().find(token_id, t)) {
+  if (rgw::keystone::TokenCache::get_instance<rgw::keystone::CephCtxConfig>().find(token_id, t)) {
     ldout(cct, 20) << "cached token.project.id=" << t.get_project_id()
                    << dendl;
       return apl_factory->create_apl_remote(cct,
@@ -500,7 +506,7 @@ RGWAuthApplier::aplptr_t RGWKeystoneAuthEngine::authenticate() const
       ldout(cct, 0) << "validated token: " << t.get_project_name()
                     << ":" << t.get_user_name()
                     << " expires: " << t.get_expires() << dendl;
-      rgw::keystone::TokenCache::get_instance().add(token_id, t);
+      rgw::keystone::TokenCache::get_instance<rgw::keystone::CephCtxConfig>().add(token_id, t);
       return apl_factory->create_apl_remote(cct,
                                             get_acl_strategy(t),
                                             get_creds_info(t, roles.admin));
index b16452b78305c11d7c2d1e029fde72fe399fce2a..35920721200e0762214c9f94dc4509df2c0a1d4e 100644 (file)
@@ -1204,59 +1204,34 @@ void rgw::keystone::TokenEnvelope::User::decode_json(JSONObj *obj)
   JSONDecoder::decode_json("roles", roles_v2, obj);
 }
 
-void rgw::keystone::TokenEnvelope::decode_json(JSONObj *root_obj)
+void rgw::keystone::TokenEnvelope::decode_v3(JSONObj* const root_obj)
 {
+  std::string expires_iso8601;
+
   JSONDecoder::decode_json("user", user, root_obj, true);
+  JSONDecoder::decode_json("expires_at", expires_iso8601, root_obj, true);
+  JSONDecoder::decode_json("roles", roles, root_obj, true);
+  JSONDecoder::decode_json("project", project, root_obj, true);
 
-  const auto version = rgw::keystone::Service::get_api_version();
-
-  if (version == rgw::keystone::ApiVersion::VER_3) {
-    string expires_iso8601;
-    if (JSONDecoder::decode_json("expires_at", expires_iso8601, root_obj)) {
-      /* VER_3 */
-      /* Presence of "expires_at" suggests we are dealing with OpenStack
-       * Identity API v3 (aka Keystone API v3) token. */
-      struct tm t;
-
-      if (parse_iso8601(expires_iso8601.c_str(), &t)) {
-        token.expires = timegm(&t);
-      } else {
-        token.expires = 0;
-        throw JSONDecoder::err("Failed to parse ISO8601 expiration date"
-                               "from Keystone response.");
-      }
-      JSONDecoder::decode_json("roles", roles, root_obj, true);
-      JSONDecoder::decode_json("project", project, root_obj, true);
-    } else {
-      /* fallback: VER_2 */
-      JSONDecoder::decode_json("token", token, root_obj, true);
-      roles = user.roles_v2;
-      project = token.tenant_v2;
-    }
-  } else if (version == rgw::keystone::ApiVersion::VER_2) {
-    if (JSONDecoder::decode_json("token", token, root_obj)) {
-      /* VER_2 */
-      roles = user.roles_v2;
-      project = token.tenant_v2;
-    } else {
-      /* fallback: VER_3 */
-      string expires_iso8601;
-      JSONDecoder::decode_json("expires_at", expires_iso8601, root_obj, true);
-
-      struct tm t;
-      if (parse_iso8601(expires_iso8601.c_str(), &t)) {
-        token.expires = timegm(&t);
-      } else {
-        token.expires = 0;
-        throw JSONDecoder::err("Failed to parse ISO8601 expiration date"
-                               "from Keystone response.");
-      }
-      JSONDecoder::decode_json("roles", roles, root_obj, true);
-      JSONDecoder::decode_json("project", project, root_obj, true);
-    }
+  struct tm t;
+  if (parse_iso8601(expires_iso8601.c_str(), &t)) {
+    token.expires = timegm(&t);
+  } else {
+    token.expires = 0;
+    throw JSONDecoder::err("Failed to parse ISO8601 expiration date"
+                           "from Keystone response.");
   }
 }
 
+void rgw::keystone::TokenEnvelope::decode_v2(JSONObj* const root_obj)
+{
+  JSONDecoder::decode_json("user", user, root_obj, true);
+  JSONDecoder::decode_json("token", token, root_obj, true);
+
+  roles = user.roles_v2;
+  project = token.tenant_v2;
+}
+
 void rgw_slo_entry::decode_json(JSONObj *obj)
 {
   JSONDecoder::decode_json("path", path, obj);
@@ -1344,15 +1319,24 @@ void rgw_sync_error_info::dump(Formatter *f) const {
   encode_json("message", message, f);
 }
 
+/* This utility function shouldn't conflict with the overload of std::to_string
+ * provided by string_ref since Boost 1.54 as it's defined outside of the std
+ * namespace. I hope we'll remove it soon - just after merging the Matt's PR
+ * for bundled Boost. It would allow us to forget that CentOS 7 has Boost 1.53. */
+static inline std::string to_string(const boost::string_ref& s)
+{
+  return std::string(s.data(), s.length());
+}
+
 void rgw::keystone::AdminTokenRequestVer2::dump(Formatter* const f) const
 {
   f->open_object_section("token_request");
     f->open_object_section("auth");
       f->open_object_section("passwordCredentials");
-        encode_json("username", cct->_conf->rgw_keystone_admin_user, f);
-        encode_json("password", cct->_conf->rgw_keystone_admin_password, f);
+        encode_json("username", to_string(conf.get_admin_user()), f);
+        encode_json("password", to_string(conf.get_admin_password()), f);
       f->close_section();
-      encode_json("tenantName", cct->_conf->rgw_keystone_admin_tenant, f);
+      encode_json("tenantName", to_string(conf.get_admin_tenant()), f);
     f->close_section();
   f->close_section();
 }
@@ -1368,22 +1352,22 @@ void rgw::keystone::AdminTokenRequestVer3::dump(Formatter* const f) const
         f->open_object_section("password");
           f->open_object_section("user");
             f->open_object_section("domain");
-              encode_json("name", cct->_conf->rgw_keystone_admin_domain, f);
+              encode_json("name", to_string(conf.get_admin_domain()), f);
             f->close_section();
-            encode_json("name", cct->_conf->rgw_keystone_admin_user, f);
-            encode_json("password", cct->_conf->rgw_keystone_admin_password, f);
+            encode_json("name", to_string(conf.get_admin_user()), f);
+            encode_json("password", to_string(conf.get_admin_password()), f);
           f->close_section();
         f->close_section();
       f->close_section();
       f->open_object_section("scope");
         f->open_object_section("project");
-          if (!cct->_conf->rgw_keystone_admin_project.empty()) {
-            encode_json("name", cct->_conf->rgw_keystone_admin_project, f);
+          if (! conf.get_admin_project().empty()) {
+            encode_json("name", to_string(conf.get_admin_project()), f);
           } else {
-            encode_json("name", cct->_conf->rgw_keystone_admin_tenant, f);
+            encode_json("name", to_string(conf.get_admin_tenant()), f);
           }
           f->open_object_section("domain");
-            encode_json("name", cct->_conf->rgw_keystone_admin_domain, f);
+            encode_json("name", to_string(conf.get_admin_domain()), f);
           f->close_section();
         f->close_section();
       f->close_section();
index 97116f5cd88b1d08228d4015db0e337c577d5ab4..11583572d2291aac54c503c3e05254ed953fad16 100644 (file)
@@ -4,6 +4,8 @@
 #include <errno.h>
 #include <fnmatch.h>
 
+#include <boost/algorithm/string/predicate.hpp>
+
 #include "common/errno.h"
 #include "common/ceph_json.h"
 #include "include/types.h"
@@ -141,68 +143,82 @@ bool rgw_decode_pki_token(CephContext * const cct,
 namespace rgw {
 namespace keystone {
 
-ApiVersion Service::get_api_version()
+ApiVersion CephCtxConfig::get_api_version() const noexcept
 {
-  const int keystone_version = g_ceph_context->_conf->rgw_keystone_api_version;
-
-  if (keystone_version == 3) {
+  switch (g_ceph_context->_conf->rgw_keystone_api_version) {
+  case 3:
     return ApiVersion::VER_3;
-  } else if (keystone_version == 2) {
+  case 2:
     return ApiVersion::VER_2;
-  } else {
-    dout(0) << "ERROR: wrong Keystone API version: " << keystone_version
+  default:
+    dout(0) << "ERROR: wrong Keystone API version: "
+            << g_ceph_context->_conf->rgw_keystone_api_version
             << "; falling back to v2" <<  dendl;
     return ApiVersion::VER_2;
   }
 }
 
-int Service::get_keystone_url(CephContext* const cct,
-                                      std::string& url)
+std::string CephCtxConfig::get_endpoint_url() const noexcept
 {
-  url = cct->_conf->rgw_keystone_url;
-  if (url.empty()) {
-    ldout(cct, 0) << "ERROR: keystone url is not configured" << dendl;
-    return -EINVAL;
-  }
+  static const std::string url = g_ceph_context->_conf->rgw_keystone_url;
 
-  if (url[url.size() - 1] != '/') {
-    url.append("/");
+  if (url.empty() || boost::algorithm::ends_with(url, "/")) {
+    return url;
+  } else {
+    static const std::string url_normalised = url + '/';
+    return url_normalised;
   }
-
-  return 0;
 }
 
-int Service::get_keystone_admin_token(CephContext* const cct,
-                                      std::string& token)
+int Service::get_admin_token(CephContext* const cct,
+                             TokenCache& token_cache,
+                             const Config& config,
+                             std::string& token)
 {
-  std::string token_url;
-
-  if (get_keystone_url(cct, token_url) < 0) {
-    return -EINVAL;
-  }
-
-  if (!cct->_conf->rgw_keystone_admin_token.empty()) {
-    token = cct->_conf->rgw_keystone_admin_token;
+  /* Let's check whether someone uses the deprecated "admin token" feauture
+   * based on a shared secret from keystone.conf file. */
+  const auto& admin_token = config.get_admin_token();
+  if (! admin_token.empty()) {
+    token = std::string(admin_token.data(), admin_token.length());
     return 0;
   }
 
   TokenEnvelope t;
 
-  /* Try cache first. */
-  if (TokenCache::get_instance<rgw::keystone::LegacyConfig>().find_admin(t)) {
+  /* Try cache first before calling Keystone for a new admin token. */
+  if (token_cache.find_admin(t)) {
     ldout(cct, 20) << "found cached admin token" << dendl;
     token = t.token.id;
     return 0;
   }
 
+  /* Call Keystone now. */
+  const auto ret = issue_admin_token_request(cct, config, t);
+  if (! ret) {
+    token_cache.add_admin(t);
+    token = t.token.id;
+  }
+
+  return ret;
+}
+
+int Service::issue_admin_token_request(CephContext* const cct,
+                                       const Config& config,
+                                       TokenEnvelope& t)
+{
+  std::string token_url = config.get_endpoint_url();
+  if (token_url.empty()) {
+    return -EINVAL;
+  }
+
   bufferlist token_bl;
   RGWGetKeystoneAdminToken token_req(cct, &token_bl);
   token_req.append_header("Content-Type", "application/json");
   JSONFormatter jf;
 
-  const auto keystone_version = Service::get_api_version();
+  const auto keystone_version = config.get_api_version();
   if (keystone_version == ApiVersion::VER_2) {
-    AdminTokenRequestVer2 req_serializer(cct);
+    AdminTokenRequestVer2 req_serializer(config);
     req_serializer.dump(&jf);
 
     std::stringstream ss;
@@ -212,7 +228,7 @@ int Service::get_keystone_admin_token(CephContext* const cct,
     token_url.append("v2.0/tokens");
 
   } else if (keystone_version == ApiVersion::VER_3) {
-    AdminTokenRequestVer3 req_serializer(cct);
+    AdminTokenRequestVer3 req_serializer(config);
     req_serializer.dump(&jf);
 
     std::stringstream ss;
@@ -235,12 +251,11 @@ int Service::get_keystone_admin_token(CephContext* const cct,
     return -EACCES;
   }
 
-  if (t.parse(cct, token_req.get_subject_token(), token_bl) != 0) {
+  if (t.parse(cct, token_req.get_subject_token(), token_bl,
+              keystone_version) != 0) {
     return -EINVAL;
   }
 
-  TokenCache::get_instance().add_admin(t);
-  token = t.token.id;
   return 0;
 }
 
@@ -258,33 +273,47 @@ bool TokenEnvelope::has_role(const std::string& r) const
 
 int TokenEnvelope::parse(CephContext* const cct,
                          const std::string& token_str,
-                         ceph::bufferlist& bl)
+                         ceph::bufferlist& bl,
+                         const ApiVersion version)
 {
   JSONParser parser;
-  if (!parser.parse(bl.c_str(), bl.length())) {
+  if (! parser.parse(bl.c_str(), bl.length())) {
     ldout(cct, 0) << "Keystone token parse error: malformed json" << dendl;
     return -EINVAL;
   }
 
-  try {
-    const auto version = rgw::keystone::Service::get_api_version();
+  JSONObjIter token_iter = parser.find_first("token");
+  JSONObjIter access_iter = parser.find_first("access");
 
+  try {
     if (version == rgw::keystone::ApiVersion::VER_2) {
-      if (!JSONDecoder::decode_json("access", *this, &parser)) {
-        /* TokenEnvelope structure doesn't follow Identity API v2, so the token
-         * must be in v3. Otherwise we can assume it's wrongly formatted. */
-        JSONDecoder::decode_json("token", *this, &parser, true);
+      if (! access_iter.end()) {
+        decode_v2(*access_iter);
+      } else if (! token_iter.end()) {
+        /* TokenEnvelope structure doesn't follow Identity API v2, so let's
+         * fallback to v3. Otherwise we can assume it's wrongly formatted.
+         * The whole mechanism is a workaround for s3_token middleware that
+         * speaks in v2 disregarding the promise to go with v3. */
+        decode_v3(*token_iter);
+
+        /* Identity v3 conveys the token inforamtion not as a part of JSON but
+         * in the X-Subject-Token HTTP header we're getting from caller. */
         token.id = token_str;
+      } else {
+        return -EINVAL;
       }
     } else if (version == rgw::keystone::ApiVersion::VER_3) {
-      if (!JSONDecoder::decode_json("token", *this, &parser)) {
-        /* If the token cannot be parsed according to V3, try V2. */
-        JSONDecoder::decode_json("access", *this, &parser, true);
-      } else {
+      if (! token_iter.end()) {
+        decode_v3(*token_iter);
         /* v3 suceeded. We have to fill token.id from external input as it
          * isn't a part of the JSON response anymore. It has been moved
          * to X-Subject-Token HTTP header instead. */
         token.id = token_str;
+      } else if (! access_iter.end()) {
+        /* If the token cannot be parsed according to V3, try V2. */
+        decode_v2(*access_iter);
+      } else {
+        return -EINVAL;
       }
     } else {
       return -ENOTSUP;
@@ -297,13 +326,6 @@ int TokenEnvelope::parse(CephContext* const cct,
   return 0;
 }
 
-TokenCache& TokenCache::get_instance()
-{
-  /* In C++11 this is thread safe. */
-  static TokenCache instance;
-  return instance;
-}
-
 bool TokenCache::find(const std::string& token_id,
                       rgw::keystone::TokenEnvelope& token)
 {
@@ -406,15 +428,18 @@ int TokenCache::RevokeThread::check_revoked()
   bufferlist bl;
   RGWGetRevokedTokens req(cct, &bl);
 
-  if (rgw::keystone::Service::get_keystone_admin_token(cct, token) < 0) {
+  if (rgw::keystone::Service::get_admin_token(cct, *cache, config, token) < 0) {
     return -EINVAL;
   }
-  if (rgw::keystone::Service::get_keystone_url(cct, url) < 0) {
+
+  url = config.get_endpoint_url();
+  if (url.empty()) {
     return -EINVAL;
   }
+
   req.append_header("X-Auth-Token", token);
 
-  const auto keystone_version = rgw::keystone::Service::get_api_version();
+  const auto keystone_version = config.get_api_version();
   if (keystone_version == rgw::keystone::ApiVersion::VER_2) {
     url.append("v2.0/tokens/revoked");
   } else if (keystone_version == rgw::keystone::ApiVersion::VER_3) {
index c59ebbd0e608d0364783c865cb6cece385f23a9f..6a99fa74a57e6fd03390f9c4755dc1d416b0a0ad 100644 (file)
@@ -4,6 +4,10 @@
 #ifndef CEPH_RGW_KEYSTONE_H
 #define CEPH_RGW_KEYSTONE_H
 
+#include <type_traits>
+
+#include <boost/utility/string_ref.hpp>
+
 #include "rgw_common.h"
 #include "rgw_http_client.h"
 #include "common/Cond.h"
@@ -35,6 +39,67 @@ enum class ApiVersion {
   VER_3
 };
 
+
+class Config {
+protected:
+  Config() = default;
+  virtual ~Config() = default;
+
+public:
+  virtual std::string get_endpoint_url() const noexcept = 0;
+  virtual ApiVersion get_api_version() const noexcept = 0;
+
+  virtual boost::string_ref get_admin_token() const noexcept = 0;
+  virtual boost::string_ref get_admin_user() const noexcept = 0;
+  virtual boost::string_ref get_admin_password() const noexcept = 0;
+  virtual boost::string_ref get_admin_tenant() const noexcept = 0;
+  virtual boost::string_ref get_admin_project() const noexcept = 0;
+  virtual boost::string_ref get_admin_domain() const noexcept = 0;
+};
+
+class CephCtxConfig : public Config {
+protected:
+  CephCtxConfig() = default;
+  virtual ~CephCtxConfig() = default;
+
+public:
+  static CephCtxConfig& get_instance() {
+    static CephCtxConfig instance;
+    return instance;
+  }
+
+  std::string get_endpoint_url() const noexcept override;
+  ApiVersion get_api_version() const noexcept override;
+
+  boost::string_ref get_admin_token() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_token;
+  }
+
+  boost::string_ref get_admin_user() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_user;
+  }
+
+  boost::string_ref get_admin_password() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_password;
+  }
+
+  boost::string_ref get_admin_tenant() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_tenant;
+  }
+
+  boost::string_ref get_admin_project() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_project;
+  }
+
+  boost::string_ref get_admin_domain() const noexcept override {
+    return g_ceph_context->_conf->rgw_keystone_admin_domain;
+  }
+};
+
+
+class TokenEnvelope;
+class TokenCache;
+
 class Service {
 public:
   class RGWKeystoneHTTPTransceiver : public RGWHTTPTransceiver {
@@ -60,12 +125,13 @@ public:
   typedef RGWKeystoneHTTPTransceiver RGWGetKeystoneAdminToken;
   typedef RGWKeystoneHTTPTransceiver RGWGetRevokedTokens;
 
-  static ApiVersion get_api_version();
-
-  static int get_keystone_url(CephContext * const cct,
-                              std::string& url);
-  static int get_keystone_admin_token(CephContext * const cct,
-                                      std::string& token);
+  static int get_admin_token(CephContext* const cct,
+                             TokenCache& token_cache,
+                             const Config& config,
+                             std::string& token);
+  static int issue_admin_token_request(CephContext* const cct,
+                                       const Config& config,
+                                       TokenEnvelope& token);
 };
 
 
@@ -115,9 +181,13 @@ public:
   User user;
   list<Role> roles;
 
+  void decode_v3(JSONObj* obj);
+  void decode_v2(JSONObj* obj);
+
 public:
-  // FIXME: default ctor needs to be eradicated here
+  /* We really need the default ctor because of the internals of TokenCache. */
   TokenEnvelope() = default;
+
   time_t get_expires() const { return token.expires; }
   const std::string& get_domain_id() const {return project.domain.id;};
   const std::string& get_domain_name() const {return project.domain.name;};
@@ -130,10 +200,10 @@ public:
     uint64_t now = ceph_clock_now().sec();
     return (now >= (uint64_t)get_expires());
   }
-  int parse(CephContext *cct,
-            const string& token_str,
-            bufferlist& bl /* in */);
-  void decode_json(JSONObj *access_obj);
+  int parse(CephContextcct,
+            const std::string& token_str,
+            ceph::buffer::list& bl /* in */,
+            ApiVersion version);
 };
 
 
@@ -143,7 +213,6 @@ class TokenCache {
     list<string>::iterator lru_iter;
   };
 
-  const rgw::keystone::Config& config;
   atomic_t down_flag;
 
   class RevokeThread : public Thread {
@@ -152,13 +221,17 @@ class TokenCache {
 
     CephContext * const cct;
     TokenCache* const cache;
+    const rgw::keystone::Config& config;
+
     Mutex lock;
     Cond cond;
 
     RevokeThread(CephContext* const cct,
-                 TokenCache* const cache)
+                 TokenCache* const cache,
+                 const rgw::keystone::Config& config)
       : cct(cct),
         cache(cache),
+        config(config),
         lock("rgw::keystone::TokenCache::RevokeThread") {
     }
     void *entry() override;
@@ -176,8 +249,8 @@ class TokenCache {
 
   const size_t max;
 
-  TokenCache()
-    : revocator(g_ceph_context, this),
+  TokenCache(const rgw::keystone::Config& config)
+    : revocator(g_ceph_context, this, config),
       cct(g_ceph_context),
       lock("rgw::keystone::TokenCache"),
       max(cct->_conf->rgw_keystone_token_cache_size) {
@@ -196,7 +269,10 @@ public:
   TokenCache(const TokenCache&) = delete;
   void operator=(const TokenCache&) = delete;
 
-  static TokenCache& get_instance();
+  template<class ConfigT>
+  static TokenCache& get_instance() {
+    static_assert(std::is_base_of<rgw::keystone::Config, ConfigT>::value,
+                  "ConfigT must be a subclass of rgw::keystone::Config");
 
     /* In C++11 this is thread safe. */
     static TokenCache instance(ConfigT::get_instance());
@@ -223,21 +299,21 @@ public:
 };
 
 class AdminTokenRequestVer2 : public AdminTokenRequest {
-  CephContext* cct;
+  const Config& conf;
 
 public:
-  AdminTokenRequestVer2(CephContext* const cct)
-    : cct(cct) {
+  AdminTokenRequestVer2(const Config& conf)
+    : conf(conf) {
   }
   void dump(Formatter *f) const override;
 };
 
 class AdminTokenRequestVer3 : public AdminTokenRequest {
-  CephContext* cct;
+  const Config& conf;
 
 public:
-  AdminTokenRequestVer3(CephContext* const cct)
-    : cct(cct) {
+  AdminTokenRequestVer3(const Config& conf)
+    : conf(conf) {
   }
   void dump(Formatter *f) const override;
 };
index edb147c4ba0daa8539f6feda04743ddc389804fe..c6918cc8d8679c8ee568a97afaba07bf5734fd66 100644 (file)
@@ -3302,7 +3302,8 @@ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(
     keystone_url.append("/");
   }
 
-  if (rgw::keystone::Service::get_api_version() == rgw::keystone::ApiVersion::VER_3) {
+  if (rgw::keystone::CephCtxConfig::get_instance().get_api_version()
+          == rgw::keystone::ApiVersion::VER_3) {
     keystone_url.append("v3/s3tokens");
   } else {
     keystone_url.append("v2.0/s3tokens");
@@ -3310,7 +3311,12 @@ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(
 
   /* get authentication token for Keystone. */
   string admin_token_id;
-  int r = rgw::keystone::Service::get_keystone_admin_token(cct, admin_token_id);
+  int r = rgw::keystone::Service::get_admin_token(
+                cct,
+                rgw::keystone::TokenCache::get_instance<rgw::keystone::CephCtxConfig>(),
+                rgw::keystone::CephCtxConfig::get_instance(),
+                admin_token_id);
+
   if (r < 0) {
     ldout(cct, 2) << "s3 keystone: cannot get token for keystone access" << dendl;
     return r;
@@ -3358,7 +3364,8 @@ int RGW_Auth_S3_Keystone_ValidateToken::validate_s3token(
   }
 
   /* now parse response */
-  if (response.parse(cct, string(), rx_buffer) < 0) {
+  if (response.parse(cct, string(), rx_buffer,
+          rgw::keystone::CephCtxConfig::get_instance().get_api_version()) < 0) {
     dout(2) << "s3 keystone: token parsing failed" << dendl;
     return -EPERM;
   }