]>
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 | |
1e59de90 | 6 | #include <atomic> |
f67539c2 | 7 | #include <string_view> |
1e59de90 TL |
8 | #include <type_traits> |
9 | #include <utility> | |
7c673cae FG |
10 | |
11 | #include <boost/optional.hpp> | |
7c673cae FG |
12 | |
13 | #include "rgw_common.h" | |
14 | #include "rgw_http_client.h" | |
9f95a23c | 15 | #include "common/ceph_mutex.h" |
c07f9fc5 | 16 | #include "global/global_init.h" |
7c673cae | 17 | |
7c673cae | 18 | |
20effc67 TL |
19 | bool rgw_is_pki_token(const std::string& token); |
20 | void rgw_get_token_id(const std::string& token, std::string& token_id); | |
21 | static inline std::string rgw_get_token_id(const std::string& token) | |
7c673cae FG |
22 | { |
23 | std::string token_id; | |
24 | rgw_get_token_id(token, token_id); | |
25 | ||
26 | return token_id; | |
27 | } | |
7c673cae FG |
28 | |
29 | namespace rgw { | |
30 | namespace keystone { | |
31 | ||
32 | enum class ApiVersion { | |
33 | VER_2, | |
34 | VER_3 | |
35 | }; | |
36 | ||
37 | ||
38 | class Config { | |
39 | protected: | |
40 | Config() = default; | |
41 | virtual ~Config() = default; | |
42 | ||
43 | public: | |
44 | virtual std::string get_endpoint_url() const noexcept = 0; | |
45 | virtual ApiVersion get_api_version() const noexcept = 0; | |
46 | ||
11fdf7f2 | 47 | virtual std::string get_admin_token() const noexcept = 0; |
f67539c2 | 48 | virtual std::string_view get_admin_user() const noexcept = 0; |
11fdf7f2 | 49 | virtual std::string get_admin_password() const noexcept = 0; |
f67539c2 TL |
50 | virtual std::string_view get_admin_tenant() const noexcept = 0; |
51 | virtual std::string_view get_admin_project() const noexcept = 0; | |
52 | virtual std::string_view get_admin_domain() const noexcept = 0; | |
7c673cae FG |
53 | }; |
54 | ||
55 | class CephCtxConfig : public Config { | |
56 | protected: | |
57 | CephCtxConfig() = default; | |
58 | virtual ~CephCtxConfig() = default; | |
59 | ||
11fdf7f2 TL |
60 | const static std::string empty; |
61 | ||
7c673cae FG |
62 | public: |
63 | static CephCtxConfig& get_instance() { | |
64 | static CephCtxConfig instance; | |
65 | return instance; | |
66 | } | |
67 | ||
68 | std::string get_endpoint_url() const noexcept override; | |
69 | ApiVersion get_api_version() const noexcept override; | |
70 | ||
11fdf7f2 | 71 | std::string get_admin_token() const noexcept override; |
7c673cae | 72 | |
f67539c2 | 73 | std::string_view get_admin_user() const noexcept override { |
7c673cae FG |
74 | return g_ceph_context->_conf->rgw_keystone_admin_user; |
75 | } | |
76 | ||
11fdf7f2 | 77 | std::string get_admin_password() const noexcept override; |
7c673cae | 78 | |
f67539c2 | 79 | std::string_view get_admin_tenant() const noexcept override { |
7c673cae FG |
80 | return g_ceph_context->_conf->rgw_keystone_admin_tenant; |
81 | } | |
82 | ||
f67539c2 | 83 | std::string_view get_admin_project() const noexcept override { |
7c673cae FG |
84 | return g_ceph_context->_conf->rgw_keystone_admin_project; |
85 | } | |
86 | ||
f67539c2 | 87 | std::string_view get_admin_domain() const noexcept override { |
7c673cae FG |
88 | return g_ceph_context->_conf->rgw_keystone_admin_domain; |
89 | } | |
90 | }; | |
91 | ||
92 | ||
93 | class TokenEnvelope; | |
94 | class TokenCache; | |
95 | ||
96 | class Service { | |
97 | public: | |
98 | class RGWKeystoneHTTPTransceiver : public RGWHTTPTransceiver { | |
99 | public: | |
100 | RGWKeystoneHTTPTransceiver(CephContext * const cct, | |
20effc67 TL |
101 | const std::string& method, |
102 | const std::string& url, | |
7c673cae | 103 | bufferlist * const token_body_bl) |
11fdf7f2 | 104 | : RGWHTTPTransceiver(cct, method, url, token_body_bl, |
7c673cae FG |
105 | cct->_conf->rgw_keystone_verify_ssl, |
106 | { "X-Subject-Token" }) { | |
107 | } | |
108 | ||
109 | const header_value_t& get_subject_token() const { | |
110 | try { | |
111 | return get_header_value("X-Subject-Token"); | |
112 | } catch (std::out_of_range&) { | |
113 | static header_value_t empty_val; | |
114 | return empty_val; | |
115 | } | |
116 | } | |
117 | }; | |
118 | ||
119 | typedef RGWKeystoneHTTPTransceiver RGWValidateKeystoneToken; | |
120 | typedef RGWKeystoneHTTPTransceiver RGWGetKeystoneAdminToken; | |
7c673cae | 121 | |
20effc67 | 122 | static int get_admin_token(const DoutPrefixProvider *dpp, |
7c673cae FG |
123 | TokenCache& token_cache, |
124 | const Config& config, | |
f51cf556 TL |
125 | optional_yield y, |
126 | std::string& token, | |
127 | bool& token_cached); | |
20effc67 | 128 | static int issue_admin_token_request(const DoutPrefixProvider *dpp, |
7c673cae | 129 | const Config& config, |
f51cf556 | 130 | optional_yield y, |
7c673cae | 131 | TokenEnvelope& token); |
20effc67 | 132 | static int get_keystone_barbican_token(const DoutPrefixProvider *dpp, |
f51cf556 | 133 | optional_yield y, |
7c673cae FG |
134 | std::string& token); |
135 | }; | |
136 | ||
137 | ||
138 | class TokenEnvelope { | |
139 | public: | |
140 | class Domain { | |
141 | public: | |
20effc67 TL |
142 | std::string id; |
143 | std::string name; | |
7c673cae FG |
144 | void decode_json(JSONObj *obj); |
145 | }; | |
146 | class Project { | |
147 | public: | |
148 | Domain domain; | |
20effc67 TL |
149 | std::string id; |
150 | std::string name; | |
7c673cae FG |
151 | void decode_json(JSONObj *obj); |
152 | }; | |
153 | ||
154 | class Token { | |
155 | public: | |
156 | Token() : expires(0) { } | |
20effc67 | 157 | std::string id; |
7c673cae FG |
158 | time_t expires; |
159 | Project tenant_v2; | |
160 | void decode_json(JSONObj *obj); | |
161 | }; | |
162 | ||
163 | class Role { | |
164 | public: | |
f51cf556 TL |
165 | Role() : is_admin(false), is_reader(false) { } |
166 | Role(const Role &r) { | |
167 | id = r.id; | |
168 | name = r.name; | |
169 | is_admin = r.is_admin; | |
170 | is_reader = r.is_reader; | |
171 | } | |
20effc67 TL |
172 | std::string id; |
173 | std::string name; | |
f51cf556 TL |
174 | bool is_admin; |
175 | bool is_reader; | |
7c673cae FG |
176 | void decode_json(JSONObj *obj); |
177 | }; | |
178 | ||
179 | class User { | |
180 | public: | |
20effc67 TL |
181 | std::string id; |
182 | std::string name; | |
7c673cae | 183 | Domain domain; |
20effc67 | 184 | std::list<Role> roles_v2; |
7c673cae FG |
185 | void decode_json(JSONObj *obj); |
186 | }; | |
187 | ||
188 | Token token; | |
189 | Project project; | |
190 | User user; | |
20effc67 | 191 | std::list<Role> roles; |
7c673cae FG |
192 | |
193 | void decode_v3(JSONObj* obj); | |
194 | void decode_v2(JSONObj* obj); | |
195 | ||
196 | public: | |
197 | /* We really need the default ctor because of the internals of TokenCache. */ | |
198 | TokenEnvelope() = default; | |
199 | ||
1e59de90 | 200 | void set_expires(time_t expires) { token.expires = expires; } |
7c673cae FG |
201 | time_t get_expires() const { return token.expires; } |
202 | const std::string& get_domain_id() const {return project.domain.id;}; | |
203 | const std::string& get_domain_name() const {return project.domain.name;}; | |
204 | const std::string& get_project_id() const {return project.id;}; | |
205 | const std::string& get_project_name() const {return project.name;}; | |
206 | const std::string& get_user_id() const {return user.id;}; | |
207 | const std::string& get_user_name() const {return user.name;}; | |
20effc67 | 208 | bool has_role(const std::string& r) const; |
7c673cae FG |
209 | bool expired() const { |
210 | const uint64_t now = ceph_clock_now().sec(); | |
1e59de90 | 211 | return std::cmp_greater_equal(now, get_expires()); |
7c673cae | 212 | } |
f51cf556 | 213 | int parse(const DoutPrefixProvider *dpp, |
7c673cae FG |
214 | const std::string& token_str, |
215 | ceph::buffer::list& bl /* in */, | |
216 | ApiVersion version); | |
f51cf556 TL |
217 | void update_roles(const std::vector<std::string> & admin, |
218 | const std::vector<std::string> & reader); | |
7c673cae FG |
219 | }; |
220 | ||
221 | ||
222 | class TokenCache { | |
223 | struct token_entry { | |
224 | TokenEnvelope token; | |
20effc67 | 225 | std::list<std::string>::iterator lru_iter; |
7c673cae FG |
226 | }; |
227 | ||
228 | std::atomic<bool> down_flag = { false }; | |
c07f9fc5 | 229 | const boost::intrusive_ptr<CephContext> cct; |
7c673cae FG |
230 | |
231 | std::string admin_token_id; | |
232 | std::string barbican_token_id; | |
233 | std::map<std::string, token_entry> tokens; | |
1e59de90 | 234 | std::map<std::string, token_entry> service_tokens; |
7c673cae | 235 | std::list<std::string> tokens_lru; |
1e59de90 | 236 | std::list<std::string> service_tokens_lru; |
7c673cae | 237 | |
9f95a23c | 238 | ceph::mutex lock = ceph::make_mutex("rgw::keystone::TokenCache"); |
7c673cae FG |
239 | |
240 | const size_t max; | |
241 | ||
11fdf7f2 | 242 | explicit TokenCache(const rgw::keystone::Config& config) |
9f95a23c | 243 | : cct(g_ceph_context), |
7c673cae | 244 | max(cct->_conf->rgw_keystone_token_cache_size) { |
7c673cae FG |
245 | } |
246 | ||
247 | ~TokenCache() { | |
248 | down_flag = true; | |
7c673cae FG |
249 | } |
250 | ||
251 | public: | |
252 | TokenCache(const TokenCache&) = delete; | |
253 | void operator=(const TokenCache&) = delete; | |
254 | ||
255 | template<class ConfigT> | |
256 | static TokenCache& get_instance() { | |
257 | static_assert(std::is_base_of<rgw::keystone::Config, ConfigT>::value, | |
258 | "ConfigT must be a subclass of rgw::keystone::Config"); | |
259 | ||
260 | /* In C++11 this is thread safe. */ | |
261 | static TokenCache instance(ConfigT::get_instance()); | |
262 | return instance; | |
263 | } | |
264 | ||
265 | bool find(const std::string& token_id, TokenEnvelope& token); | |
1e59de90 | 266 | bool find_service(const std::string& token_id, TokenEnvelope& token); |
7c673cae FG |
267 | boost::optional<TokenEnvelope> find(const std::string& token_id) { |
268 | TokenEnvelope token_envlp; | |
269 | if (find(token_id, token_envlp)) { | |
270 | return token_envlp; | |
271 | } | |
272 | return boost::none; | |
273 | } | |
1e59de90 TL |
274 | boost::optional<TokenEnvelope> find_service(const std::string& token_id) { |
275 | TokenEnvelope token_envlp; | |
276 | if (find_service(token_id, token_envlp)) { | |
277 | return token_envlp; | |
278 | } | |
279 | return boost::none; | |
280 | } | |
7c673cae FG |
281 | bool find_admin(TokenEnvelope& token); |
282 | bool find_barbican(TokenEnvelope& token); | |
283 | void add(const std::string& token_id, const TokenEnvelope& token); | |
1e59de90 | 284 | void add_service(const std::string& token_id, const TokenEnvelope& token); |
7c673cae FG |
285 | void add_admin(const TokenEnvelope& token); |
286 | void add_barbican(const TokenEnvelope& token); | |
20effc67 | 287 | void invalidate(const DoutPrefixProvider *dpp, const std::string& token_id); |
f51cf556 | 288 | void invalidate_admin(const DoutPrefixProvider *dpp); |
7c673cae FG |
289 | bool going_down() const; |
290 | private: | |
1e59de90 TL |
291 | void add_locked(const std::string& token_id, const TokenEnvelope& token, |
292 | std::map<std::string, token_entry>& tokens, std::list<std::string>& tokens_lru); | |
293 | bool find_locked(const std::string& token_id, TokenEnvelope& token, | |
294 | std::map<std::string, token_entry>& tokens, std::list<std::string>& tokens_lru); | |
7c673cae FG |
295 | }; |
296 | ||
297 | ||
298 | class AdminTokenRequest { | |
299 | public: | |
300 | virtual ~AdminTokenRequest() = default; | |
301 | virtual void dump(Formatter* f) const = 0; | |
302 | }; | |
303 | ||
304 | class AdminTokenRequestVer2 : public AdminTokenRequest { | |
305 | const Config& conf; | |
306 | ||
307 | public: | |
11fdf7f2 | 308 | explicit AdminTokenRequestVer2(const Config& conf) |
7c673cae FG |
309 | : conf(conf) { |
310 | } | |
311 | void dump(Formatter *f) const override; | |
312 | }; | |
313 | ||
314 | class AdminTokenRequestVer3 : public AdminTokenRequest { | |
315 | const Config& conf; | |
316 | ||
317 | public: | |
11fdf7f2 | 318 | explicit AdminTokenRequestVer3(const Config& conf) |
7c673cae FG |
319 | : conf(conf) { |
320 | } | |
321 | void dump(Formatter *f) const override; | |
322 | }; | |
323 | ||
324 | class BarbicanTokenRequestVer2 : public AdminTokenRequest { | |
325 | CephContext *cct; | |
326 | ||
327 | public: | |
11fdf7f2 | 328 | explicit BarbicanTokenRequestVer2(CephContext * const _cct) |
7c673cae FG |
329 | : cct(_cct) { |
330 | } | |
11fdf7f2 | 331 | void dump(Formatter *f) const override; |
7c673cae FG |
332 | }; |
333 | ||
334 | class BarbicanTokenRequestVer3 : public AdminTokenRequest { | |
335 | CephContext *cct; | |
336 | ||
337 | public: | |
11fdf7f2 | 338 | explicit BarbicanTokenRequestVer3(CephContext * const _cct) |
7c673cae FG |
339 | : cct(_cct) { |
340 | } | |
11fdf7f2 | 341 | void dump(Formatter *f) const override; |
7c673cae FG |
342 | }; |
343 | ||
344 | ||
345 | }; /* namespace keystone */ | |
346 | }; /* namespace rgw */ |