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