summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_auth_keystone.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/rgw/rgw_auth_keystone.h202
1 files changed, 202 insertions, 0 deletions
diff --git a/src/rgw/rgw_auth_keystone.h b/src/rgw/rgw_auth_keystone.h
new file mode 100644
index 000000000..9d79bc878
--- /dev/null
+++ b/src/rgw/rgw_auth_keystone.h
@@ -0,0 +1,202 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+#pragma once
+
+#include <string_view>
+#include <utility>
+#include <boost/optional.hpp>
+
+#include "rgw_auth.h"
+#include "rgw_rest_s3.h"
+#include "rgw_common.h"
+#include "rgw_keystone.h"
+
+namespace rgw {
+namespace auth {
+namespace keystone {
+
+/* Dedicated namespace for Keystone-related auth engines. We need it because
+ * Keystone offers three different authentication mechanisms (token, EC2 and
+ * regular user/pass). RadosGW actually does support the first two. */
+
+class TokenEngine : public rgw::auth::Engine {
+ CephContext* const cct;
+
+ using acl_strategy_t = rgw::auth::RemoteApplier::acl_strategy_t;
+ using auth_info_t = rgw::auth::RemoteApplier::AuthInfo;
+ using result_t = rgw::auth::Engine::result_t;
+ using token_envelope_t = rgw::keystone::TokenEnvelope;
+
+ const rgw::auth::TokenExtractor* const auth_token_extractor;
+ const rgw::auth::TokenExtractor* const service_token_extractor;
+ const rgw::auth::RemoteApplier::Factory* const apl_factory;
+ rgw::keystone::Config& config;
+ rgw::keystone::TokenCache& token_cache;
+
+ /* Helper methods. */
+ bool is_applicable(const std::string& token) const noexcept;
+
+ boost::optional<token_envelope_t>
+ get_from_keystone(const DoutPrefixProvider* dpp, const std::string& token, bool allow_expired) 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
+ ) const noexcept;
+ result_t authenticate(const DoutPrefixProvider* dpp,
+ const std::string& token,
+ const std::string& service_token,
+ const req_state* s) const;
+
+public:
+ TokenEngine(CephContext* const cct,
+ const rgw::auth::TokenExtractor* const auth_token_extractor,
+ const rgw::auth::TokenExtractor* const service_token_extractor,
+ const rgw::auth::RemoteApplier::Factory* const apl_factory,
+ rgw::keystone::Config& config,
+ rgw::keystone::TokenCache& token_cache)
+ : cct(cct),
+ auth_token_extractor(auth_token_extractor),
+ service_token_extractor(service_token_extractor),
+ apl_factory(apl_factory),
+ config(config),
+ token_cache(token_cache) {
+ }
+
+ const char* get_name() const noexcept override {
+ return "rgw::auth::keystone::TokenEngine";
+ }
+
+ result_t authenticate(const DoutPrefixProvider* dpp, const req_state* const s,
+ optional_yield y) const override {
+ return authenticate(dpp, auth_token_extractor->get_token(s), service_token_extractor->get_token(s), s);
+ }
+}; /* class TokenEngine */
+
+class SecretCache {
+ using token_envelope_t = rgw::keystone::TokenEnvelope;
+
+ struct secret_entry {
+ token_envelope_t token;
+ std::string secret;
+ utime_t expires;
+ std::list<std::string>::iterator lru_iter;
+ };
+
+ const boost::intrusive_ptr<CephContext> cct;
+
+ std::map<std::string, secret_entry> secrets;
+ std::list<std::string> secrets_lru;
+
+ std::mutex lock;
+
+ const size_t max;
+
+ const utime_t s3_token_expiry_length;
+
+ SecretCache()
+ : cct(g_ceph_context),
+ lock(),
+ max(cct->_conf->rgw_keystone_token_cache_size),
+ s3_token_expiry_length(300, 0) {
+ }
+
+ ~SecretCache() {}
+
+public:
+ SecretCache(const SecretCache&) = delete;
+ void operator=(const SecretCache&) = delete;
+
+ static SecretCache& get_instance() {
+ /* In C++11 this is thread safe. */
+ static SecretCache instance;
+ return instance;
+ }
+
+ bool find(const std::string& token_id, token_envelope_t& token, std::string& secret);
+ boost::optional<boost::tuple<token_envelope_t, std::string>> find(const std::string& token_id) {
+ token_envelope_t token_envlp;
+ std::string secret;
+ if (find(token_id, token_envlp, secret)) {
+ return boost::make_tuple(token_envlp, secret);
+ }
+ return boost::none;
+ }
+ void add(const std::string& token_id, const token_envelope_t& token, const std::string& secret);
+}; /* class SecretCache */
+
+class EC2Engine : public rgw::auth::s3::AWSEngine {
+ using acl_strategy_t = rgw::auth::RemoteApplier::acl_strategy_t;
+ using auth_info_t = rgw::auth::RemoteApplier::AuthInfo;
+ using result_t = rgw::auth::Engine::result_t;
+ using token_envelope_t = rgw::keystone::TokenEnvelope;
+
+ const rgw::auth::RemoteApplier::Factory* const apl_factory;
+ rgw::keystone::Config& config;
+ rgw::keystone::TokenCache& token_cache;
+ rgw::auth::keystone::SecretCache& secret_cache;
+
+ /* Helper methods. */
+ 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,
+ const std::string& access_key_id
+ ) const noexcept;
+ std::pair<boost::optional<token_envelope_t>, int>
+ get_from_keystone(const DoutPrefixProvider* dpp,
+ const std::string_view& access_key_id,
+ const std::string& string_to_sign,
+ const std::string_view& signature) const;
+
+ struct access_token_result {
+ boost::optional<token_envelope_t> token;
+ boost::optional<std::string> secret_key;
+ int failure_reason = 0;
+ };
+ access_token_result
+ get_access_token(const DoutPrefixProvider* dpp,
+ const std::string_view& access_key_id,
+ const std::string& string_to_sign,
+ const std::string_view& signature,
+ const signature_factory_t& signature_factory) const;
+ result_t authenticate(const DoutPrefixProvider* dpp,
+ const std::string_view& access_key_id,
+ const std::string_view& signature,
+ const std::string_view& session_token,
+ const string_to_sign_t& string_to_sign,
+ const signature_factory_t& signature_factory,
+ const completer_factory_t& completer_factory,
+ const req_state* s,
+ optional_yield y) const override;
+ std::pair<boost::optional<std::string>, int> get_secret_from_keystone(const DoutPrefixProvider* dpp,
+ const std::string& user_id,
+ const std::string_view& access_key_id) const;
+public:
+ EC2Engine(CephContext* const cct,
+ const rgw::auth::s3::AWSEngine::VersionAbstractor* const ver_abstractor,
+ const rgw::auth::RemoteApplier::Factory* const apl_factory,
+ rgw::keystone::Config& config,
+ /* The token cache is used ONLY for the retrieving admin token.
+ * Due to the architecture of AWS Auth S3 credentials cannot be
+ * cached at all. */
+ rgw::keystone::TokenCache& token_cache,
+ rgw::auth::keystone::SecretCache& secret_cache)
+ : AWSEngine(cct, *ver_abstractor),
+ apl_factory(apl_factory),
+ config(config),
+ token_cache(token_cache),
+ secret_cache(secret_cache) {
+ }
+
+ using AWSEngine::authenticate;
+
+ const char* get_name() const noexcept override {
+ return "rgw::auth::keystone::EC2Engine";
+ }
+
+}; /* class EC2Engine */
+
+}; /* namespace keystone */
+}; /* namespace auth */
+}; /* namespace rgw */