From 2d51d1d7d7476caa373e7d0d3fb322e8a9672dbf Mon Sep 17 00:00:00 2001 From: Radoslaw Zarzynski Date: Mon, 23 Jan 2017 17:37:49 +0100 Subject: [PATCH] rgw: refactor error handling in rgw::auth::keystone. Signed-off-by: Radoslaw Zarzynski --- src/rgw/rgw_auth_keystone.cc | 94 +++++++++++++++++++++--------------- src/rgw/rgw_auth_keystone.h | 15 ++++-- src/rgw/rgw_keystone.h | 8 +++ 3 files changed, 75 insertions(+), 42 deletions(-) diff --git a/src/rgw/rgw_auth_keystone.cc b/src/rgw/rgw_auth_keystone.cc index 1c6a9cc41ae0a..a92d1858edfc7 100644 --- a/src/rgw/rgw_auth_keystone.cc +++ b/src/rgw/rgw_auth_keystone.cc @@ -59,11 +59,13 @@ TokenEngine::decode_pki_token(const std::string& token) const return token_body; } -TokenEngine::token_envelope_t +boost::optional 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 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, 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 admin; } accepted_roles(cct); - const auto t = get_from_keystone(access_key_id, string_to_sign, - signature); + boost::optional 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)); } } diff --git a/src/rgw/rgw_auth_keystone.h b/src/rgw/rgw_auth_keystone.h index c3b00e47f2383..3645c07ef537d 100644 --- a/src/rgw/rgw_auth_keystone.h +++ b/src/rgw/rgw_auth_keystone.h @@ -5,6 +5,9 @@ #ifndef CEPH_RGW_AUTH_KEYSTONE_H #define CEPH_RGW_AUTH_KEYSTONE_H +#include +#include + #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 + 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& 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& 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, 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, diff --git a/src/rgw/rgw_keystone.h b/src/rgw/rgw_keystone.h index 0fa97920cf587..91cf9b13c4486 100644 --- a/src/rgw/rgw_keystone.h +++ b/src/rgw/rgw_keystone.h @@ -6,6 +6,7 @@ #include +#include #include #include "rgw_common.h" @@ -280,6 +281,13 @@ public: } bool find(const std::string& token_id, TokenEnvelope& token); + boost::optional 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); -- 2.39.5