]>
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 FG |
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" | |
9f95a23c | 14 | #include "common/ceph_mutex.h" |
c07f9fc5 | 15 | #include "global/global_init.h" |
7c673cae FG |
16 | |
17 | #include <atomic> | |
18 | ||
7c673cae FG |
19 | bool rgw_is_pki_token(const string& token); |
20 | void rgw_get_token_id(const string& token, string& token_id); | |
21 | static inline std::string rgw_get_token_id(const string& token) | |
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; |
7c673cae | 48 | virtual boost::string_ref get_admin_user() const noexcept = 0; |
11fdf7f2 | 49 | virtual std::string get_admin_password() const noexcept = 0; |
7c673cae FG |
50 | virtual boost::string_ref get_admin_tenant() const noexcept = 0; |
51 | virtual boost::string_ref get_admin_project() const noexcept = 0; | |
52 | virtual boost::string_ref get_admin_domain() const noexcept = 0; | |
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 FG |
72 | |
73 | boost::string_ref get_admin_user() const noexcept override { | |
74 | return g_ceph_context->_conf->rgw_keystone_admin_user; | |
75 | } | |
76 | ||
11fdf7f2 | 77 | std::string get_admin_password() const noexcept override; |
7c673cae FG |
78 | |
79 | boost::string_ref get_admin_tenant() const noexcept override { | |
80 | return g_ceph_context->_conf->rgw_keystone_admin_tenant; | |
81 | } | |
82 | ||
83 | boost::string_ref get_admin_project() const noexcept override { | |
84 | return g_ceph_context->_conf->rgw_keystone_admin_project; | |
85 | } | |
86 | ||
87 | boost::string_ref get_admin_domain() const noexcept override { | |
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, | |
11fdf7f2 TL |
101 | const string& method, |
102 | const 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 FG |
121 | |
122 | static int get_admin_token(CephContext* const cct, | |
123 | TokenCache& token_cache, | |
124 | const Config& config, | |
125 | std::string& token); | |
126 | static int issue_admin_token_request(CephContext* const cct, | |
127 | const Config& config, | |
128 | TokenEnvelope& token); | |
129 | static int get_keystone_barbican_token(CephContext * const cct, | |
130 | std::string& token); | |
131 | }; | |
132 | ||
133 | ||
134 | class TokenEnvelope { | |
135 | public: | |
136 | class Domain { | |
137 | public: | |
138 | string id; | |
139 | string name; | |
140 | void decode_json(JSONObj *obj); | |
141 | }; | |
142 | class Project { | |
143 | public: | |
144 | Domain domain; | |
145 | string id; | |
146 | string name; | |
147 | void decode_json(JSONObj *obj); | |
148 | }; | |
149 | ||
150 | class Token { | |
151 | public: | |
152 | Token() : expires(0) { } | |
153 | string id; | |
154 | time_t expires; | |
155 | Project tenant_v2; | |
156 | void decode_json(JSONObj *obj); | |
157 | }; | |
158 | ||
159 | class Role { | |
160 | public: | |
161 | string id; | |
162 | string name; | |
163 | void decode_json(JSONObj *obj); | |
164 | }; | |
165 | ||
166 | class User { | |
167 | public: | |
168 | string id; | |
169 | string name; | |
170 | Domain domain; | |
171 | list<Role> roles_v2; | |
172 | void decode_json(JSONObj *obj); | |
173 | }; | |
174 | ||
175 | Token token; | |
176 | Project project; | |
177 | User user; | |
178 | list<Role> roles; | |
179 | ||
180 | void decode_v3(JSONObj* obj); | |
181 | void decode_v2(JSONObj* obj); | |
182 | ||
183 | public: | |
184 | /* We really need the default ctor because of the internals of TokenCache. */ | |
185 | TokenEnvelope() = default; | |
186 | ||
187 | time_t get_expires() const { return token.expires; } | |
188 | const std::string& get_domain_id() const {return project.domain.id;}; | |
189 | const std::string& get_domain_name() const {return project.domain.name;}; | |
190 | const std::string& get_project_id() const {return project.id;}; | |
191 | const std::string& get_project_name() const {return project.name;}; | |
192 | const std::string& get_user_id() const {return user.id;}; | |
193 | const std::string& get_user_name() const {return user.name;}; | |
194 | bool has_role(const string& r) const; | |
195 | bool expired() const { | |
196 | const uint64_t now = ceph_clock_now().sec(); | |
197 | return now >= static_cast<uint64_t>(get_expires()); | |
198 | } | |
199 | int parse(CephContext* cct, | |
200 | const std::string& token_str, | |
201 | ceph::buffer::list& bl /* in */, | |
202 | ApiVersion version); | |
203 | }; | |
204 | ||
205 | ||
206 | class TokenCache { | |
207 | struct token_entry { | |
208 | TokenEnvelope token; | |
209 | list<string>::iterator lru_iter; | |
210 | }; | |
211 | ||
212 | std::atomic<bool> down_flag = { false }; | |
c07f9fc5 | 213 | const boost::intrusive_ptr<CephContext> cct; |
7c673cae FG |
214 | |
215 | std::string admin_token_id; | |
216 | std::string barbican_token_id; | |
217 | std::map<std::string, token_entry> tokens; | |
218 | std::list<std::string> tokens_lru; | |
219 | ||
9f95a23c | 220 | ceph::mutex lock = ceph::make_mutex("rgw::keystone::TokenCache"); |
7c673cae FG |
221 | |
222 | const size_t max; | |
223 | ||
11fdf7f2 | 224 | explicit TokenCache(const rgw::keystone::Config& config) |
9f95a23c | 225 | : cct(g_ceph_context), |
7c673cae | 226 | max(cct->_conf->rgw_keystone_token_cache_size) { |
7c673cae FG |
227 | } |
228 | ||
229 | ~TokenCache() { | |
230 | down_flag = true; | |
7c673cae FG |
231 | } |
232 | ||
233 | public: | |
234 | TokenCache(const TokenCache&) = delete; | |
235 | void operator=(const TokenCache&) = delete; | |
236 | ||
237 | template<class ConfigT> | |
238 | static TokenCache& get_instance() { | |
239 | static_assert(std::is_base_of<rgw::keystone::Config, ConfigT>::value, | |
240 | "ConfigT must be a subclass of rgw::keystone::Config"); | |
241 | ||
242 | /* In C++11 this is thread safe. */ | |
243 | static TokenCache instance(ConfigT::get_instance()); | |
244 | return instance; | |
245 | } | |
246 | ||
247 | bool find(const std::string& token_id, TokenEnvelope& token); | |
248 | boost::optional<TokenEnvelope> find(const std::string& token_id) { | |
249 | TokenEnvelope token_envlp; | |
250 | if (find(token_id, token_envlp)) { | |
251 | return token_envlp; | |
252 | } | |
253 | return boost::none; | |
254 | } | |
255 | bool find_admin(TokenEnvelope& token); | |
256 | bool find_barbican(TokenEnvelope& token); | |
257 | void add(const std::string& token_id, const TokenEnvelope& token); | |
258 | void add_admin(const TokenEnvelope& token); | |
259 | void add_barbican(const TokenEnvelope& token); | |
260 | void invalidate(const std::string& token_id); | |
261 | bool going_down() const; | |
262 | private: | |
263 | void add_locked(const std::string& token_id, const TokenEnvelope& token); | |
264 | bool find_locked(const std::string& token_id, TokenEnvelope& token); | |
265 | ||
266 | }; | |
267 | ||
268 | ||
269 | class AdminTokenRequest { | |
270 | public: | |
271 | virtual ~AdminTokenRequest() = default; | |
272 | virtual void dump(Formatter* f) const = 0; | |
273 | }; | |
274 | ||
275 | class AdminTokenRequestVer2 : public AdminTokenRequest { | |
276 | const Config& conf; | |
277 | ||
278 | public: | |
11fdf7f2 | 279 | explicit AdminTokenRequestVer2(const Config& conf) |
7c673cae FG |
280 | : conf(conf) { |
281 | } | |
282 | void dump(Formatter *f) const override; | |
283 | }; | |
284 | ||
285 | class AdminTokenRequestVer3 : public AdminTokenRequest { | |
286 | const Config& conf; | |
287 | ||
288 | public: | |
11fdf7f2 | 289 | explicit AdminTokenRequestVer3(const Config& conf) |
7c673cae FG |
290 | : conf(conf) { |
291 | } | |
292 | void dump(Formatter *f) const override; | |
293 | }; | |
294 | ||
295 | class BarbicanTokenRequestVer2 : public AdminTokenRequest { | |
296 | CephContext *cct; | |
297 | ||
298 | public: | |
11fdf7f2 | 299 | explicit BarbicanTokenRequestVer2(CephContext * const _cct) |
7c673cae FG |
300 | : cct(_cct) { |
301 | } | |
11fdf7f2 | 302 | void dump(Formatter *f) const override; |
7c673cae FG |
303 | }; |
304 | ||
305 | class BarbicanTokenRequestVer3 : public AdminTokenRequest { | |
306 | CephContext *cct; | |
307 | ||
308 | public: | |
11fdf7f2 | 309 | explicit BarbicanTokenRequestVer3(CephContext * const _cct) |
7c673cae FG |
310 | : cct(_cct) { |
311 | } | |
11fdf7f2 | 312 | void dump(Formatter *f) const override; |
7c673cae FG |
313 | }; |
314 | ||
315 | ||
316 | }; /* namespace keystone */ | |
317 | }; /* namespace rgw */ | |
318 | ||
319 | #endif |