]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: refactor error handling in rgw::auth::keystone.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Mon, 23 Jan 2017 16:37:49 +0000 (17:37 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Fri, 24 Mar 2017 15:55:42 +0000 (16:55 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_auth_keystone.cc
src/rgw/rgw_auth_keystone.h
src/rgw/rgw_keystone.h

index 1c6a9cc41ae0a00789011201f67f664ba9d471f3..a92d1858edfc7a502622ab96c498b438b5204167 100644 (file)
@@ -59,11 +59,13 @@ TokenEngine::decode_pki_token(const std::string& token) const
   return token_body;
 }
 
-TokenEngine::token_envelope_t
+boost::optional<TokenEngine::token_envelope_t>
 TokenEngine::get_from_keystone(const std::string& token) const
 {
-  using RGWValidateKeystoneToken
-    = rgw::keystone::Service::RGWValidateKeystoneToken;
+  /* Unfortunately, we can't use the short form of "using" here. It's because
+   * we're aliasing a class' member, not namespace. */
+  using RGWValidateKeystoneToken = \
+    rgw::keystone::Service::RGWValidateKeystoneToken;
 
   /* The container for plain response obtained from Keystone. It will be
    * parsed token_envelope_t::parse method. */
@@ -112,7 +114,7 @@ TokenEngine::get_from_keystone(const std::string& token) const
       validate.get_http_status() ==
           /* Most likely: non-existent token supplied by the client. */
           RGWValidateKeystoneToken::HTTP_STATUS_NOTFOUND) {
-    throw -EACCES;
+    return boost::none;
   }
 
   TokenEngine::token_envelope_t token_body;
@@ -202,7 +204,7 @@ TokenEngine::result_t
 TokenEngine::authenticate(const std::string& token,
                           const req_state* const s) const
 {
-  TokenEngine::token_envelope_t t;
+  boost::optional<TokenEngine::token_envelope_t> t;
 
   /* This will be initialized on the first call to this method. In C++11 it's
    * also thread-safe. */
@@ -229,11 +231,12 @@ TokenEngine::authenticate(const std::string& token,
   ldout(cct, 20) << "token_id=" << token_id << dendl;
 
   /* Check cache first. */
-  if (token_cache.find(token_id, t)) {
-    ldout(cct, 20) << "cached token.project.id=" << t.get_project_id()
+  t = token_cache.find(token_id);
+  if (t) {
+    ldout(cct, 20) << "cached token.project.id=" << t->get_project_id()
                    << dendl;
-    auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(t),
-                                              get_creds_info(t, roles.admin));
+    auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(*t),
+                                              get_creds_info(*t, roles.admin));
     return result_t::grant(std::move(apl));
   }
 
@@ -250,23 +253,27 @@ TokenEngine::authenticate(const std::string& token,
     t = get_from_keystone(token);
   }
 
+  if (! t) {
+    return result_t::deny(-EACCES);
+  }
+
   /* Verify expiration. */
-  if (t.expired()) {
-    ldout(cct, 0) << "got expired token: " << t.get_project_name()
-                  << ":" << t.get_user_name()
-                  << " expired: " << t.get_expires() << dendl;
+  if (t->expired()) {
+    ldout(cct, 0) << "got expired token: " << t->get_project_name()
+                  << ":" << t->get_user_name()
+                  << " expired: " << t->get_expires() << dendl;
     return result_t::deny();
   }
 
   /* Check for necessary roles. */
   for (const auto& role : roles.plain) {
-    if (t.has_role(role) == true) {
-      ldout(cct, 0) << "validated token: " << t.get_project_name()
-                    << ":" << t.get_user_name()
-                    << " expires: " << t.get_expires() << dendl;
-      token_cache.add(token_id, t);
-      auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(t),
-                                            get_creds_info(t, roles.admin));
+    if (t->has_role(role) == true) {
+      ldout(cct, 0) << "validated token: " << t->get_project_name()
+                    << ":" << t->get_user_name()
+                    << " expires: " << t->get_expires() << dendl;
+      token_cache.add(token_id, *t);
+      auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(*t),
+                                            get_creds_info(*t, roles.admin));
       return result_t::grant(std::move(apl));
     }
   }
@@ -281,7 +288,7 @@ TokenEngine::authenticate(const std::string& token,
 /*
  * Try to validate S3 auth against keystone s3token interface
  */
-rgw::keystone::TokenEnvelope
+std::pair<boost::optional<rgw::keystone::TokenEnvelope>, int>
 EC2Engine::get_from_keystone(const std::string& access_key_id,
                              const std::string& string_to_sign,
                              const std::string& signature) const
@@ -350,17 +357,22 @@ EC2Engine::get_from_keystone(const std::string& access_key_id,
   /* if the supplied signature is wrong, we will get 401 from Keystone */
   if (validate.get_http_status() ==
           decltype(validate)::HTTP_STATUS_UNAUTHORIZED) {
-    throw -ERR_SIGNATURE_NO_MATCH;
+    return std::make_pair(boost::none, -ERR_SIGNATURE_NO_MATCH);
+  } else if (validate.get_http_status() ==
+          decltype(validate)::HTTP_STATUS_NOTFOUND) {
+    return std::make_pair(boost::none, -ERR_INVALID_ACCESS_KEY);
   }
 
   /* now parse response */
   rgw::keystone::TokenEnvelope token_envelope;
-  if (token_envelope.parse(cct, std::string(), token_body_bl, api_version) < 0) {
-    ldout(cct, 2) << "s3 keystone: token parsing failed" << dendl;
-    throw -EPERM;
+  ret = token_envelope.parse(cct, std::string(), token_body_bl, api_version);
+  if (ret < 0) {
+    ldout(cct, 2) << "s3 keystone: token parsing failed, ret=0" << ret
+                  << dendl;
+    throw ret;
   }
 
-  return std::move(token_envelope);
+  return std::make_pair(std::move(token_envelope), 0);
 }
 
 EC2Engine::acl_strategy_t
@@ -422,20 +434,26 @@ rgw::auth::Engine::result_t EC2Engine::authenticate(const std::string& access_ke
     std::vector<std::string> admin;
   } accepted_roles(cct);
 
-  const auto t = get_from_keystone(access_key_id, string_to_sign,
-                                   signature);
+  boost::optional<token_envelope_t> t;
+  int failure_reason;
+  std::tie(t, failure_reason) = \
+    get_from_keystone(access_key_id, string_to_sign, signature);
+  if (! t) {
+    return result_t::deny(failure_reason);
+  }
+
   /* Verify expiration. */
-  if (t.expired()) {
-    ldout(cct, 0) << "got expired token: " << t.get_project_name()
-                  << ":" << t.get_user_name()
-                  << " expired: " << t.get_expires() << dendl;
+  if (t->expired()) {
+    ldout(cct, 0) << "got expired token: " << t->get_project_name()
+                  << ":" << t->get_user_name()
+                  << " expired: " << t->get_expires() << dendl;
     return result_t::deny();
   }
 
   /* check if we have a valid role */
   bool found = false;
   for (const auto& role : accepted_roles.plain) {
-    if (t.has_role(role) == true) {
+    if (t->has_role(role) == true) {
       found = true;
       break;
     }
@@ -448,12 +466,12 @@ rgw::auth::Engine::result_t EC2Engine::authenticate(const std::string& access_ke
     return result_t::deny();
   } else {
     /* everything seems fine, continue with this user */
-    ldout(cct, 5) << "s3 keystone: validated token: " << t.get_project_name()
-                  << ":" << t.get_user_name()
-                  << " expires: " << t.get_expires() << dendl;
+    ldout(cct, 5) << "s3 keystone: validated token: " << t->get_project_name()
+                  << ":" << t->get_user_name()
+                  << " expires: " << t->get_expires() << dendl;
 
-    auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(t),
-                                              get_creds_info(t, accepted_roles.admin));
+    auto apl = apl_factory->create_apl_remote(cct, s, get_acl_strategy(*t),
+                                              get_creds_info(*t, accepted_roles.admin));
     return result_t::grant(std::move(apl));
   }
 }
index c3b00e47f238304991734f51cd7691abd91cadb0..3645c07ef537de55568d16165ae8f582fc4bd965 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef CEPH_RGW_AUTH_KEYSTONE_H
 #define CEPH_RGW_AUTH_KEYSTONE_H
 
+#include <utility>
+#include <boost/optional.hpp>
+
 #include "rgw_auth.h"
 #include "rgw_rest_s3.h"
 #include "rgw_common.h"
@@ -34,7 +37,10 @@ class TokenEngine : public rgw::auth::Engine {
   /* Helper methods. */
   bool is_applicable(const std::string& token) const noexcept;
   token_envelope_t decode_pki_token(const std::string& token) const;
-  token_envelope_t get_from_keystone(const std::string& token) const;
+
+  boost::optional<token_envelope_t>
+  get_from_keystone(const std::string& token) const;
+
   acl_strategy_t get_acl_strategy(const token_envelope_t& token) const;
   auth_info_t get_creds_info(const token_envelope_t& token,
                              const std::vector<std::string>& admin_roles
@@ -80,9 +86,10 @@ class EC2Engine : public rgw::auth::s3::Version2ndEngine {
   auth_info_t get_creds_info(const token_envelope_t& token,
                              const std::vector<std::string>& admin_roles
                             ) const noexcept;
-  token_envelope_t get_from_keystone(const std::string& access_key_id,
-                                     const std::string& string_to_sign,
-                                     const std::string& signature) const;
+  std::pair<boost::optional<token_envelope_t>, int>
+  get_from_keystone(const std::string& access_key_id,
+                    const std::string& string_to_sign,
+                    const std::string& signature) const;
   result_t authenticate(const std::string& access_key_id,
                         const std::string& signature,
                         const std::string& string_to_sign,
index 0fa97920cf5875ff1aadfd8aca953041b677baea..91cf9b13c44866cebd4309789cb47412142d32b7 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <type_traits>
 
+#include <boost/optional.hpp>
 #include <boost/utility/string_ref.hpp>
 
 #include "rgw_common.h"
@@ -280,6 +281,13 @@ public:
   }
 
   bool find(const std::string& token_id, TokenEnvelope& token);
+  boost::optional<TokenEnvelope> find(const std::string& token_id) {
+    TokenEnvelope token_envlp;
+    if (find(token_id, token_envlp)) {
+      return token_envlp;
+    }
+    return boost::none;
+  }
   bool find_admin(TokenEnvelope& token);
   void add(const std::string& token_id, const TokenEnvelope& token);
   void add_admin(const TokenEnvelope& token);