]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_keystone.h
bump version to 12.1.1-pve1 while rebasing patches
[ceph.git] / ceph / src / rgw / rgw_keystone.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_RGW_KEYSTONE_H
5 #define CEPH_RGW_KEYSTONE_H
6
7 #include <type_traits>
8
9 #include <boost/optional.hpp>
10 #include <boost/utility/string_ref.hpp>
11
12 #include "rgw_common.h"
13 #include "rgw_http_client.h"
14 #include "common/Cond.h"
15
16 #include <atomic>
17
18 int rgw_open_cms_envelope(CephContext *cct,
19 const std::string& src,
20 std::string& dst); /* out */
21 int rgw_decode_b64_cms(CephContext *cct,
22 const string& signed_b64,
23 bufferlist& bl);
24 bool rgw_is_pki_token(const string& token);
25 void rgw_get_token_id(const string& token, string& token_id);
26 static inline std::string rgw_get_token_id(const string& token)
27 {
28 std::string token_id;
29 rgw_get_token_id(token, token_id);
30
31 return token_id;
32 }
33 bool rgw_decode_pki_token(CephContext *cct,
34 const string& token,
35 bufferlist& bl);
36
37 namespace rgw {
38 namespace keystone {
39
40 enum class ApiVersion {
41 VER_2,
42 VER_3
43 };
44
45
46 class Config {
47 protected:
48 Config() = default;
49 virtual ~Config() = default;
50
51 public:
52 virtual std::string get_endpoint_url() const noexcept = 0;
53 virtual ApiVersion get_api_version() const noexcept = 0;
54
55 virtual boost::string_ref get_admin_token() const noexcept = 0;
56 virtual boost::string_ref get_admin_user() const noexcept = 0;
57 virtual boost::string_ref get_admin_password() const noexcept = 0;
58 virtual boost::string_ref get_admin_tenant() const noexcept = 0;
59 virtual boost::string_ref get_admin_project() const noexcept = 0;
60 virtual boost::string_ref get_admin_domain() const noexcept = 0;
61 };
62
63 class CephCtxConfig : public Config {
64 protected:
65 CephCtxConfig() = default;
66 virtual ~CephCtxConfig() = default;
67
68 public:
69 static CephCtxConfig& get_instance() {
70 static CephCtxConfig instance;
71 return instance;
72 }
73
74 std::string get_endpoint_url() const noexcept override;
75 ApiVersion get_api_version() const noexcept override;
76
77 boost::string_ref get_admin_token() const noexcept override {
78 return g_ceph_context->_conf->rgw_keystone_admin_token;
79 }
80
81 boost::string_ref get_admin_user() const noexcept override {
82 return g_ceph_context->_conf->rgw_keystone_admin_user;
83 }
84
85 boost::string_ref get_admin_password() const noexcept override {
86 return g_ceph_context->_conf->rgw_keystone_admin_password;
87 }
88
89 boost::string_ref get_admin_tenant() const noexcept override {
90 return g_ceph_context->_conf->rgw_keystone_admin_tenant;
91 }
92
93 boost::string_ref get_admin_project() const noexcept override {
94 return g_ceph_context->_conf->rgw_keystone_admin_project;
95 }
96
97 boost::string_ref get_admin_domain() const noexcept override {
98 return g_ceph_context->_conf->rgw_keystone_admin_domain;
99 }
100 };
101
102
103 class TokenEnvelope;
104 class TokenCache;
105
106 class Service {
107 public:
108 class RGWKeystoneHTTPTransceiver : public RGWHTTPTransceiver {
109 public:
110 RGWKeystoneHTTPTransceiver(CephContext * const cct,
111 bufferlist * const token_body_bl)
112 : RGWHTTPTransceiver(cct, token_body_bl,
113 cct->_conf->rgw_keystone_verify_ssl,
114 { "X-Subject-Token" }) {
115 }
116
117 const header_value_t& get_subject_token() const {
118 try {
119 return get_header_value("X-Subject-Token");
120 } catch (std::out_of_range&) {
121 static header_value_t empty_val;
122 return empty_val;
123 }
124 }
125 };
126
127 typedef RGWKeystoneHTTPTransceiver RGWValidateKeystoneToken;
128 typedef RGWKeystoneHTTPTransceiver RGWGetKeystoneAdminToken;
129 typedef RGWKeystoneHTTPTransceiver RGWGetRevokedTokens;
130
131 static int get_admin_token(CephContext* const cct,
132 TokenCache& token_cache,
133 const Config& config,
134 std::string& token);
135 static int issue_admin_token_request(CephContext* const cct,
136 const Config& config,
137 TokenEnvelope& token);
138 static int get_keystone_barbican_token(CephContext * const cct,
139 std::string& token);
140 };
141
142
143 class TokenEnvelope {
144 public:
145 class Domain {
146 public:
147 string id;
148 string name;
149 void decode_json(JSONObj *obj);
150 };
151 class Project {
152 public:
153 Domain domain;
154 string id;
155 string name;
156 void decode_json(JSONObj *obj);
157 };
158
159 class Token {
160 public:
161 Token() : expires(0) { }
162 string id;
163 time_t expires;
164 Project tenant_v2;
165 void decode_json(JSONObj *obj);
166 };
167
168 class Role {
169 public:
170 string id;
171 string name;
172 void decode_json(JSONObj *obj);
173 };
174
175 class User {
176 public:
177 string id;
178 string name;
179 Domain domain;
180 list<Role> roles_v2;
181 void decode_json(JSONObj *obj);
182 };
183
184 Token token;
185 Project project;
186 User user;
187 list<Role> roles;
188
189 void decode_v3(JSONObj* obj);
190 void decode_v2(JSONObj* obj);
191
192 public:
193 /* We really need the default ctor because of the internals of TokenCache. */
194 TokenEnvelope() = default;
195
196 time_t get_expires() const { return token.expires; }
197 const std::string& get_domain_id() const {return project.domain.id;};
198 const std::string& get_domain_name() const {return project.domain.name;};
199 const std::string& get_project_id() const {return project.id;};
200 const std::string& get_project_name() const {return project.name;};
201 const std::string& get_user_id() const {return user.id;};
202 const std::string& get_user_name() const {return user.name;};
203 bool has_role(const string& r) const;
204 bool expired() const {
205 const uint64_t now = ceph_clock_now().sec();
206 return now >= static_cast<uint64_t>(get_expires());
207 }
208 int parse(CephContext* cct,
209 const std::string& token_str,
210 ceph::buffer::list& bl /* in */,
211 ApiVersion version);
212 };
213
214
215 class TokenCache {
216 struct token_entry {
217 TokenEnvelope token;
218 list<string>::iterator lru_iter;
219 };
220
221 std::atomic<bool> down_flag = { false };
222
223 class RevokeThread : public Thread {
224 friend class TokenCache;
225 typedef RGWPostHTTPData RGWGetRevokedTokens;
226
227 CephContext * const cct;
228 TokenCache* const cache;
229 const rgw::keystone::Config& config;
230
231 Mutex lock;
232 Cond cond;
233
234 RevokeThread(CephContext* const cct,
235 TokenCache* const cache,
236 const rgw::keystone::Config& config)
237 : cct(cct),
238 cache(cache),
239 config(config),
240 lock("rgw::keystone::TokenCache::RevokeThread") {
241 }
242 void *entry() override;
243 void stop();
244 int check_revoked();
245 } revocator;
246
247 CephContext * const cct;
248
249 std::string admin_token_id;
250 std::string barbican_token_id;
251 std::map<std::string, token_entry> tokens;
252 std::list<std::string> tokens_lru;
253
254 Mutex lock;
255
256 const size_t max;
257
258 TokenCache(const rgw::keystone::Config& config)
259 : revocator(g_ceph_context, this, config),
260 cct(g_ceph_context),
261 lock("rgw::keystone::TokenCache"),
262 max(cct->_conf->rgw_keystone_token_cache_size) {
263 /* revocation logic needs to be smarter, but meanwhile,
264 * make it optional.
265 * see http://tracker.ceph.com/issues/9493
266 * http://tracker.ceph.com/issues/19499
267 */
268 if (cct->_conf->rgw_keystone_revocation_interval > 0
269 && cct->_conf->rgw_keystone_token_cache_size ) {
270 /* The thread name has been kept for backward compliance. */
271 revocator.create("rgw_swift_k_rev");
272 }
273 }
274
275 ~TokenCache() {
276 down_flag = true;
277
278 revocator.stop();
279 revocator.join();
280 }
281
282 public:
283 TokenCache(const TokenCache&) = delete;
284 void operator=(const TokenCache&) = delete;
285
286 template<class ConfigT>
287 static TokenCache& get_instance() {
288 static_assert(std::is_base_of<rgw::keystone::Config, ConfigT>::value,
289 "ConfigT must be a subclass of rgw::keystone::Config");
290
291 /* In C++11 this is thread safe. */
292 static TokenCache instance(ConfigT::get_instance());
293 return instance;
294 }
295
296 bool find(const std::string& token_id, TokenEnvelope& token);
297 boost::optional<TokenEnvelope> find(const std::string& token_id) {
298 TokenEnvelope token_envlp;
299 if (find(token_id, token_envlp)) {
300 return token_envlp;
301 }
302 return boost::none;
303 }
304 bool find_admin(TokenEnvelope& token);
305 bool find_barbican(TokenEnvelope& token);
306 void add(const std::string& token_id, const TokenEnvelope& token);
307 void add_admin(const TokenEnvelope& token);
308 void add_barbican(const TokenEnvelope& token);
309 void invalidate(const std::string& token_id);
310 bool going_down() const;
311 private:
312 void add_locked(const std::string& token_id, const TokenEnvelope& token);
313 bool find_locked(const std::string& token_id, TokenEnvelope& token);
314
315 };
316
317
318 class AdminTokenRequest {
319 public:
320 virtual ~AdminTokenRequest() = default;
321 virtual void dump(Formatter* f) const = 0;
322 };
323
324 class AdminTokenRequestVer2 : public AdminTokenRequest {
325 const Config& conf;
326
327 public:
328 AdminTokenRequestVer2(const Config& conf)
329 : conf(conf) {
330 }
331 void dump(Formatter *f) const override;
332 };
333
334 class AdminTokenRequestVer3 : public AdminTokenRequest {
335 const Config& conf;
336
337 public:
338 AdminTokenRequestVer3(const Config& conf)
339 : conf(conf) {
340 }
341 void dump(Formatter *f) const override;
342 };
343
344 class BarbicanTokenRequestVer2 : public AdminTokenRequest {
345 CephContext *cct;
346
347 public:
348 BarbicanTokenRequestVer2(CephContext * const _cct)
349 : cct(_cct) {
350 }
351 void dump(Formatter *f) const;
352 };
353
354 class BarbicanTokenRequestVer3 : public AdminTokenRequest {
355 CephContext *cct;
356
357 public:
358 BarbicanTokenRequestVer3(CephContext * const _cct)
359 : cct(_cct) {
360 }
361 void dump(Formatter *f) const;
362 };
363
364
365 }; /* namespace keystone */
366 }; /* namespace rgw */
367
368 #endif