Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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     // Only stop and join if revocator thread is started.
281     if (revocator.is_started()) {
282       revocator.stop();
283       revocator.join();
284     }
285   }
286
287 public:
288   TokenCache(const TokenCache&) = delete;
289   void operator=(const TokenCache&) = delete;
290
291   template<class ConfigT>
292   static TokenCache& get_instance() {
293     static_assert(std::is_base_of<rgw::keystone::Config, ConfigT>::value,
294                   "ConfigT must be a subclass of rgw::keystone::Config");
295
296     /* In C++11 this is thread safe. */
297     static TokenCache instance(ConfigT::get_instance());
298     return instance;
299   }
300
301   bool find(const std::string& token_id, TokenEnvelope& token);
302   boost::optional<TokenEnvelope> find(const std::string& token_id) {
303     TokenEnvelope token_envlp;
304     if (find(token_id, token_envlp)) {
305       return token_envlp;
306     }
307     return boost::none;
308   }
309   bool find_admin(TokenEnvelope& token);
310   bool find_barbican(TokenEnvelope& token);
311   void add(const std::string& token_id, const TokenEnvelope& token);
312   void add_admin(const TokenEnvelope& token);
313   void add_barbican(const TokenEnvelope& token);
314   void invalidate(const std::string& token_id);
315   bool going_down() const;
316 private:
317   void add_locked(const std::string& token_id, const TokenEnvelope& token);
318   bool find_locked(const std::string& token_id, TokenEnvelope& token);
319
320 };
321
322
323 class AdminTokenRequest {
324 public:
325   virtual ~AdminTokenRequest() = default;
326   virtual void dump(Formatter* f) const = 0;
327 };
328
329 class AdminTokenRequestVer2 : public AdminTokenRequest {
330   const Config& conf;
331
332 public:
333   AdminTokenRequestVer2(const Config& conf)
334     : conf(conf) {
335   }
336   void dump(Formatter *f) const override;
337 };
338
339 class AdminTokenRequestVer3 : public AdminTokenRequest {
340   const Config& conf;
341
342 public:
343   AdminTokenRequestVer3(const Config& conf)
344     : conf(conf) {
345   }
346   void dump(Formatter *f) const override;
347 };
348
349 class BarbicanTokenRequestVer2 : public AdminTokenRequest {
350   CephContext *cct;
351
352 public:
353   BarbicanTokenRequestVer2(CephContext * const _cct)
354     : cct(_cct) {
355   }
356   void dump(Formatter *f) const;
357 };
358
359 class BarbicanTokenRequestVer3 : public AdminTokenRequest {
360   CephContext *cct;
361
362 public:
363   BarbicanTokenRequestVer3(CephContext * const _cct)
364     : cct(_cct) {
365   }
366   void dump(Formatter *f) const;
367 };
368
369
370 }; /* namespace keystone */
371 }; /* namespace rgw */
372
373 #endif