]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
7c673cae | 3 | |
1e59de90 | 4 | #pragma once |
7c673cae | 5 | |
f67539c2 | 6 | #include <string_view> |
7c673cae FG |
7 | #include <utility> |
8 | #include <boost/optional.hpp> | |
9 | ||
10 | #include "rgw_auth.h" | |
11 | #include "rgw_rest_s3.h" | |
12 | #include "rgw_common.h" | |
13 | #include "rgw_keystone.h" | |
14 | ||
15 | namespace rgw { | |
16 | namespace auth { | |
17 | namespace keystone { | |
18 | ||
19 | /* Dedicated namespace for Keystone-related auth engines. We need it because | |
20 | * Keystone offers three different authentication mechanisms (token, EC2 and | |
21 | * regular user/pass). RadosGW actually does support the first two. */ | |
22 | ||
23 | class TokenEngine : public rgw::auth::Engine { | |
24 | CephContext* const cct; | |
25 | ||
26 | using acl_strategy_t = rgw::auth::RemoteApplier::acl_strategy_t; | |
27 | using auth_info_t = rgw::auth::RemoteApplier::AuthInfo; | |
28 | using result_t = rgw::auth::Engine::result_t; | |
29 | using token_envelope_t = rgw::keystone::TokenEnvelope; | |
30 | ||
1e59de90 TL |
31 | const rgw::auth::TokenExtractor* const auth_token_extractor; |
32 | const rgw::auth::TokenExtractor* const service_token_extractor; | |
7c673cae FG |
33 | const rgw::auth::RemoteApplier::Factory* const apl_factory; |
34 | rgw::keystone::Config& config; | |
35 | rgw::keystone::TokenCache& token_cache; | |
36 | ||
37 | /* Helper methods. */ | |
38 | bool is_applicable(const std::string& token) const noexcept; | |
7c673cae FG |
39 | |
40 | boost::optional<token_envelope_t> | |
1e59de90 | 41 | get_from_keystone(const DoutPrefixProvider* dpp, const std::string& token, bool allow_expired) const; |
7c673cae FG |
42 | |
43 | acl_strategy_t get_acl_strategy(const token_envelope_t& token) const; | |
44 | auth_info_t get_creds_info(const token_envelope_t& token, | |
45 | const std::vector<std::string>& admin_roles | |
46 | ) const noexcept; | |
11fdf7f2 TL |
47 | result_t authenticate(const DoutPrefixProvider* dpp, |
48 | const std::string& token, | |
1e59de90 | 49 | const std::string& service_token, |
7c673cae FG |
50 | const req_state* s) const; |
51 | ||
52 | public: | |
53 | TokenEngine(CephContext* const cct, | |
1e59de90 TL |
54 | const rgw::auth::TokenExtractor* const auth_token_extractor, |
55 | const rgw::auth::TokenExtractor* const service_token_extractor, | |
7c673cae FG |
56 | const rgw::auth::RemoteApplier::Factory* const apl_factory, |
57 | rgw::keystone::Config& config, | |
58 | rgw::keystone::TokenCache& token_cache) | |
59 | : cct(cct), | |
1e59de90 TL |
60 | auth_token_extractor(auth_token_extractor), |
61 | service_token_extractor(service_token_extractor), | |
7c673cae FG |
62 | apl_factory(apl_factory), |
63 | config(config), | |
64 | token_cache(token_cache) { | |
65 | } | |
66 | ||
67 | const char* get_name() const noexcept override { | |
68 | return "rgw::auth::keystone::TokenEngine"; | |
69 | } | |
70 | ||
f67539c2 TL |
71 | result_t authenticate(const DoutPrefixProvider* dpp, const req_state* const s, |
72 | optional_yield y) const override { | |
1e59de90 | 73 | return authenticate(dpp, auth_token_extractor->get_token(s), service_token_extractor->get_token(s), s); |
7c673cae FG |
74 | } |
75 | }; /* class TokenEngine */ | |
76 | ||
9f95a23c TL |
77 | class SecretCache { |
78 | using token_envelope_t = rgw::keystone::TokenEnvelope; | |
79 | ||
80 | struct secret_entry { | |
81 | token_envelope_t token; | |
82 | std::string secret; | |
83 | utime_t expires; | |
20effc67 | 84 | std::list<std::string>::iterator lru_iter; |
9f95a23c TL |
85 | }; |
86 | ||
87 | const boost::intrusive_ptr<CephContext> cct; | |
88 | ||
89 | std::map<std::string, secret_entry> secrets; | |
90 | std::list<std::string> secrets_lru; | |
91 | ||
92 | std::mutex lock; | |
93 | ||
94 | const size_t max; | |
95 | ||
96 | const utime_t s3_token_expiry_length; | |
97 | ||
98 | SecretCache() | |
99 | : cct(g_ceph_context), | |
100 | lock(), | |
101 | max(cct->_conf->rgw_keystone_token_cache_size), | |
102 | s3_token_expiry_length(300, 0) { | |
103 | } | |
104 | ||
105 | ~SecretCache() {} | |
106 | ||
107 | public: | |
108 | SecretCache(const SecretCache&) = delete; | |
109 | void operator=(const SecretCache&) = delete; | |
110 | ||
111 | static SecretCache& get_instance() { | |
112 | /* In C++11 this is thread safe. */ | |
113 | static SecretCache instance; | |
114 | return instance; | |
115 | } | |
116 | ||
117 | bool find(const std::string& token_id, token_envelope_t& token, std::string& secret); | |
118 | boost::optional<boost::tuple<token_envelope_t, std::string>> find(const std::string& token_id) { | |
119 | token_envelope_t token_envlp; | |
120 | std::string secret; | |
121 | if (find(token_id, token_envlp, secret)) { | |
122 | return boost::make_tuple(token_envlp, secret); | |
123 | } | |
124 | return boost::none; | |
125 | } | |
126 | void add(const std::string& token_id, const token_envelope_t& token, const std::string& secret); | |
127 | }; /* class SecretCache */ | |
7c673cae | 128 | |
31f18b77 | 129 | class EC2Engine : public rgw::auth::s3::AWSEngine { |
7c673cae FG |
130 | using acl_strategy_t = rgw::auth::RemoteApplier::acl_strategy_t; |
131 | using auth_info_t = rgw::auth::RemoteApplier::AuthInfo; | |
132 | using result_t = rgw::auth::Engine::result_t; | |
133 | using token_envelope_t = rgw::keystone::TokenEnvelope; | |
134 | ||
135 | const rgw::auth::RemoteApplier::Factory* const apl_factory; | |
136 | rgw::keystone::Config& config; | |
137 | rgw::keystone::TokenCache& token_cache; | |
9f95a23c | 138 | rgw::auth::keystone::SecretCache& secret_cache; |
7c673cae FG |
139 | |
140 | /* Helper methods. */ | |
141 | acl_strategy_t get_acl_strategy(const token_envelope_t& token) const; | |
142 | auth_info_t get_creds_info(const token_envelope_t& token, | |
2a845540 TL |
143 | const std::vector<std::string>& admin_roles, |
144 | const std::string& access_key_id | |
7c673cae FG |
145 | ) const noexcept; |
146 | std::pair<boost::optional<token_envelope_t>, int> | |
9f95a23c | 147 | get_from_keystone(const DoutPrefixProvider* dpp, |
f67539c2 | 148 | const std::string_view& access_key_id, |
7c673cae | 149 | const std::string& string_to_sign, |
f67539c2 | 150 | const std::string_view& signature) const; |
1e59de90 TL |
151 | |
152 | struct access_token_result { | |
153 | boost::optional<token_envelope_t> token; | |
154 | boost::optional<std::string> secret_key; | |
155 | int failure_reason = 0; | |
156 | }; | |
157 | access_token_result | |
9f95a23c | 158 | get_access_token(const DoutPrefixProvider* dpp, |
f67539c2 | 159 | const std::string_view& access_key_id, |
9f95a23c | 160 | const std::string& string_to_sign, |
f67539c2 | 161 | const std::string_view& signature, |
9f95a23c | 162 | const signature_factory_t& signature_factory) const; |
11fdf7f2 | 163 | result_t authenticate(const DoutPrefixProvider* dpp, |
f67539c2 TL |
164 | const std::string_view& access_key_id, |
165 | const std::string_view& signature, | |
166 | const std::string_view& session_token, | |
31f18b77 | 167 | const string_to_sign_t& string_to_sign, |
9f95a23c | 168 | const signature_factory_t& signature_factory, |
31f18b77 | 169 | const completer_factory_t& completer_factory, |
f67539c2 TL |
170 | const req_state* s, |
171 | optional_yield y) const override; | |
9f95a23c TL |
172 | std::pair<boost::optional<std::string>, int> get_secret_from_keystone(const DoutPrefixProvider* dpp, |
173 | const std::string& user_id, | |
f67539c2 | 174 | const std::string_view& access_key_id) const; |
7c673cae FG |
175 | public: |
176 | EC2Engine(CephContext* const cct, | |
31f18b77 | 177 | const rgw::auth::s3::AWSEngine::VersionAbstractor* const ver_abstractor, |
7c673cae FG |
178 | const rgw::auth::RemoteApplier::Factory* const apl_factory, |
179 | rgw::keystone::Config& config, | |
180 | /* The token cache is used ONLY for the retrieving admin token. | |
181 | * Due to the architecture of AWS Auth S3 credentials cannot be | |
182 | * cached at all. */ | |
9f95a23c TL |
183 | rgw::keystone::TokenCache& token_cache, |
184 | rgw::auth::keystone::SecretCache& secret_cache) | |
31f18b77 | 185 | : AWSEngine(cct, *ver_abstractor), |
7c673cae FG |
186 | apl_factory(apl_factory), |
187 | config(config), | |
9f95a23c TL |
188 | token_cache(token_cache), |
189 | secret_cache(secret_cache) { | |
7c673cae FG |
190 | } |
191 | ||
31f18b77 | 192 | using AWSEngine::authenticate; |
7c673cae FG |
193 | |
194 | const char* get_name() const noexcept override { | |
195 | return "rgw::auth::keystone::EC2Engine"; | |
196 | } | |
197 | ||
198 | }; /* class EC2Engine */ | |
199 | ||
200 | }; /* namespace keystone */ | |
201 | }; /* namespace auth */ | |
202 | }; /* namespace rgw */ |