Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_auth.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <array>
5
6 #include "rgw_common.h"
7 #include "rgw_auth.h"
8 #include "rgw_user.h"
9 #include "rgw_http_client.h"
10 #include "rgw_keystone.h"
11
12 #include "include/str_list.h"
13
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rgw
16
17
18 namespace rgw {
19 namespace auth {
20
21 std::unique_ptr<rgw::auth::Identity>
22 transform_old_authinfo(const req_state* const s)
23 {
24   /* This class is not intended for public use. Should be removed altogether
25    * with this function after moving all our APIs to the new authentication
26    * infrastructure. */
27   class DummyIdentityApplier : public rgw::auth::Identity {
28     CephContext* const cct;
29
30     /* For this particular case it's OK to use rgw_user structure to convey
31      * the identity info as this was the policy for doing that before the
32      * new auth. */
33     const rgw_user id;
34     const int perm_mask;
35     const bool is_admin;
36   public:
37     DummyIdentityApplier(CephContext* const cct,
38                          const rgw_user& auth_id,
39                          const int perm_mask,
40                          const bool is_admin)
41       : cct(cct),
42         id(auth_id),
43         perm_mask(perm_mask),
44         is_admin(is_admin) {
45     }
46
47     uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override {
48       return rgw_perms_from_aclspec_default_strategy(id, aclspec);
49     }
50
51     bool is_admin_of(const rgw_user& acct_id) const override {
52       return is_admin;
53     }
54
55     bool is_owner_of(const rgw_user& acct_id) const override {
56       return id == acct_id;
57     }
58
59     bool is_identity(const idset_t& ids) const override {
60       for (auto& p : ids) {
61         if (p.is_wildcard()) {
62           return true;
63         } else if (p.is_tenant() && p.get_tenant() == id.tenant) {
64           return true;
65         } else if (p.is_user() &&
66                    (p.get_tenant() == id.tenant) &&
67                    (p.get_id() == id.id)) {
68           return true;
69         }
70       }
71       return false;
72     }
73
74     uint32_t get_perm_mask() const override {
75       return perm_mask;
76     }
77
78     void to_str(std::ostream& out) const override {
79       out << "RGWDummyIdentityApplier(auth_id=" << id
80           << ", perm_mask=" << perm_mask
81           << ", is_admin=" << is_admin << ")";
82     }
83   };
84
85   return std::unique_ptr<rgw::auth::Identity>(
86         new DummyIdentityApplier(s->cct,
87                                  s->user->user_id,
88                                  s->perm_mask,
89   /* System user has admin permissions by default - it's supposed to pass
90    * through any security check. */
91                                  s->system_request));
92 }
93
94 } /* namespace auth */
95 } /* namespace rgw */
96
97
98 uint32_t rgw_perms_from_aclspec_default_strategy(
99   const rgw_user& uid,
100   const rgw::auth::Identity::aclspec_t& aclspec)
101 {
102   dout(5) << "Searching permissions for uid=" << uid <<  dendl;
103
104   const auto iter = aclspec.find(uid.to_str());
105   if (std::end(aclspec) != iter) {
106     dout(5) << "Found permission: " << iter->second << dendl;
107     return iter->second;
108   }
109
110   dout(5) << "Permissions for user not found" << dendl;
111   return 0;
112 }
113
114
115 static inline const std::string make_spec_item(const std::string& tenant,
116                                                const std::string& id)
117 {
118   return tenant + ":" + id;
119 }
120
121
122 static inline std::pair<bool, rgw::auth::Engine::result_t>
123 strategy_handle_rejected(rgw::auth::Engine::result_t&& engine_result,
124                          const rgw::auth::Strategy::Control policy,
125                          rgw::auth::Engine::result_t&& strategy_result)
126 {
127   using Control = rgw::auth::Strategy::Control;
128   switch (policy) {
129     case Control::REQUISITE:
130       /* Don't try next. */
131       return std::make_pair(false, std::move(engine_result));
132
133     case Control::SUFFICIENT:
134       /* Don't try next. */
135       return std::make_pair(false, std::move(engine_result));
136
137     case Control::FALLBACK:
138       /* Don't try next. */
139       return std::make_pair(false, std::move(strategy_result));
140
141     default:
142       /* Huh, memory corruption? */
143       abort();
144   }
145 }
146
147 static inline std::pair<bool, rgw::auth::Engine::result_t>
148 strategy_handle_denied(rgw::auth::Engine::result_t&& engine_result,
149                        const rgw::auth::Strategy::Control policy,
150                        rgw::auth::Engine::result_t&& strategy_result)
151 {
152   using Control = rgw::auth::Strategy::Control;
153   switch (policy) {
154     case Control::REQUISITE:
155       /* Don't try next. */
156       return std::make_pair(false, std::move(engine_result));
157
158     case Control::SUFFICIENT:
159       /* Just try next. */
160       return std::make_pair(true, std::move(engine_result));
161
162     case Control::FALLBACK:
163       return std::make_pair(true, std::move(strategy_result));
164
165     default:
166       /* Huh, memory corruption? */
167       abort();
168   }
169 }
170
171 static inline std::pair<bool, rgw::auth::Engine::result_t>
172 strategy_handle_granted(rgw::auth::Engine::result_t&& engine_result,
173                         const rgw::auth::Strategy::Control policy,
174                         rgw::auth::Engine::result_t&& strategy_result)
175 {
176   using Control = rgw::auth::Strategy::Control;
177   switch (policy) {
178     case Control::REQUISITE:
179       /* Try next. */
180       return std::make_pair(true, std::move(engine_result));
181
182     case Control::SUFFICIENT:
183       /* Don't try next. */
184       return std::make_pair(false, std::move(engine_result));
185
186     case Control::FALLBACK:
187       /* Don't try next. */
188       return std::make_pair(false, std::move(engine_result));
189
190     default:
191       /* Huh, memory corruption? */
192       abort();
193   }
194 }
195
196 rgw::auth::Engine::result_t
197 rgw::auth::Strategy::authenticate(const req_state* const s) const
198 {
199   result_t strategy_result = result_t::deny();
200
201   for (const stack_item_t& kv : auth_stack) {
202     const rgw::auth::Engine& engine = kv.first;
203     const auto& policy = kv.second;
204
205     dout(20) << get_name() << ": trying " << engine.get_name() << dendl;
206
207     result_t engine_result = result_t::deny();
208     try {
209       engine_result = engine.authenticate(s);
210     } catch (const int err) {
211       engine_result = result_t::deny(err);
212     }
213
214     bool try_next = true;
215     switch (engine_result.get_status()) {
216       case result_t::Status::REJECTED: {
217         dout(20) << engine.get_name() << " rejected with reason="
218                  << engine_result.get_reason() << dendl;
219
220         std::tie(try_next, strategy_result) = \
221           strategy_handle_rejected(std::move(engine_result), policy,
222                                    std::move(strategy_result));
223         break;
224       }
225       case result_t::Status::DENIED: {
226         dout(20) << engine.get_name() << " denied with reason="
227                  << engine_result.get_reason() << dendl;
228
229         std::tie(try_next, strategy_result) = \
230           strategy_handle_denied(std::move(engine_result), policy,
231                                  std::move(strategy_result));
232         break;
233       }
234       case result_t::Status::GRANTED: {
235         dout(20) << engine.get_name() << " granted access" << dendl;
236
237         std::tie(try_next, strategy_result) = \
238           strategy_handle_granted(std::move(engine_result), policy,
239                                   std::move(strategy_result));
240         break;
241       }
242       default: {
243         abort();
244       }
245     }
246
247     if (! try_next) {
248       break;
249     }
250   }
251
252   return strategy_result;
253 }
254
255 int
256 rgw::auth::Strategy::apply(const rgw::auth::Strategy& auth_strategy,
257                            req_state* const s) noexcept
258 {
259   try {
260     auto result = auth_strategy.authenticate(s);
261     if (result.get_status() != decltype(result)::Status::GRANTED) {
262       /* Access denied is acknowledged by returning a std::unique_ptr with
263        * nullptr inside. */
264       ldout(s->cct, 5) << "Failed the auth strategy, reason="
265                        << result.get_reason() << dendl;
266       return result.get_reason();
267     }
268
269     try {
270       rgw::auth::IdentityApplier::aplptr_t applier = result.get_applier();
271       rgw::auth::Completer::cmplptr_t completer = result.get_completer();
272
273       /* Account used by a given RGWOp is decoupled from identity employed
274        * in the authorization phase (RGWOp::verify_permissions). */
275       applier->load_acct_info(*s->user);
276       s->perm_mask = applier->get_perm_mask();
277
278       /* This is the signle place where we pass req_state as a pointer
279        * to non-const and thus its modification is allowed. In the time
280        * of writing only RGWTempURLEngine needed that feature. */
281       applier->modify_request_state(s);
282       if (completer) {
283         completer->modify_request_state(s);
284       }
285
286       s->auth.identity = std::move(applier);
287       s->auth.completer = std::move(completer);
288
289       return 0;
290     } catch (const int err) {
291       ldout(s->cct, 5) << "applier throwed err=" << err << dendl;
292       return err;
293     }
294   } catch (const int err) {
295     ldout(s->cct, 5) << "auth engine throwed err=" << err << dendl;
296     return err;
297   }
298
299   /* We never should be here. */
300   return -EPERM;
301 }
302
303 void
304 rgw::auth::Strategy::add_engine(const Control ctrl_flag,
305                                 const Engine& engine) noexcept
306 {
307   auth_stack.push_back(std::make_pair(std::cref(engine), ctrl_flag));
308 }
309
310
311 /* rgw::auth::RemoteAuthApplier */
312 uint32_t rgw::auth::RemoteApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
313 {
314   uint32_t perm = 0;
315
316   /* For backward compatibility with ACLOwner. */
317   perm |= rgw_perms_from_aclspec_default_strategy(info.acct_user,
318                                                   aclspec);
319
320   /* We also need to cover cases where rgw_keystone_implicit_tenants
321    * was enabled. */
322   if (info.acct_user.tenant.empty()) {
323     const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
324
325     perm |= rgw_perms_from_aclspec_default_strategy(tenanted_acct_user,
326                                                     aclspec);
327   }
328
329   /* Now it's a time for invoking additional strategy that was supplied by
330    * a specific auth engine. */
331   if (extra_acl_strategy) {
332     perm |= extra_acl_strategy(aclspec);
333   }
334
335   ldout(cct, 20) << "from ACL got perm=" << perm << dendl;
336   return perm;
337 }
338
339 bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user& uid) const
340 {
341   return info.is_admin;
342 }
343
344 bool rgw::auth::RemoteApplier::is_owner_of(const rgw_user& uid) const
345 {
346   if (info.acct_user.tenant.empty()) {
347     const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id);
348
349     if (tenanted_acct_user == uid) {
350       return true;
351     }
352   }
353
354   return info.acct_user == uid;
355 }
356
357 bool rgw::auth::RemoteApplier::is_identity(const idset_t& ids) const {
358   for (auto& id : ids) {
359     if (id.is_wildcard()) {
360       return true;
361
362       // We also need to cover cases where rgw_keystone_implicit_tenants
363       // was enabled. */
364     } else if (id.is_tenant() &&
365                (info.acct_user.tenant.empty() ?
366                 info.acct_user.id :
367                 info.acct_user.tenant) == id.get_tenant()) {
368       return true;
369     } else if (id.is_user() &&
370                info.acct_user.id == id.get_id() &&
371                (info.acct_user.tenant.empty() ?
372                 info.acct_user.id :
373                 info.acct_user.tenant) == id.get_tenant()) {
374       return true;
375     }
376   }
377   return false;
378 }
379
380 void rgw::auth::RemoteApplier::to_str(std::ostream& out) const
381 {
382   out << "rgw::auth::RemoteApplier(acct_user=" << info.acct_user
383       << ", acct_name=" << info.acct_name
384       << ", perm_mask=" << info.perm_mask
385       << ", is_admin=" << info.is_admin << ")";
386 }
387
388 void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
389                                               RGWUserInfo& user_info) const      /* out */
390 {
391   rgw_user new_acct_user = acct_user;
392
393   if (info.acct_type) {
394     //ldap/keystone for s3 users
395     user_info.type = info.acct_type;
396   }
397
398   /* An upper layer may enforce creating new accounts within their own
399    * tenants. */
400   if (new_acct_user.tenant.empty() && implicit_tenants) {
401     new_acct_user.tenant = new_acct_user.id;
402   }
403
404   user_info.user_id = new_acct_user;
405   user_info.display_name = info.acct_name;
406
407   int ret = rgw_store_user_info(store, user_info, nullptr, nullptr,
408                                 real_time(), true);
409   if (ret < 0) {
410     ldout(cct, 0) << "ERROR: failed to store new user info: user="
411                   << user_info.user_id << " ret=" << ret << dendl;
412     throw ret;
413   }
414 }
415
416 /* TODO(rzarzynski): we need to handle display_name changes. */
417 void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const      /* out */
418 {
419   /* It's supposed that RGWRemoteAuthApplier tries to load account info
420    * that belongs to the authenticated identity. Another policy may be
421    * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
422   const rgw_user& acct_user = info.acct_user;
423
424   /* Normally, empty "tenant" field of acct_user means the authenticated
425    * identity has the legacy, global tenant. However, due to inclusion
426    * of multi-tenancy, we got some special compatibility kludge for remote
427    * backends like Keystone.
428    * If the global tenant is the requested one, we try the same tenant as
429    * the user name first. If that RGWUserInfo exists, we use it. This way,
430    * migrated OpenStack users can get their namespaced containers and nobody's
431    * the wiser.
432    * If that fails, we look up in the requested (possibly empty) tenant.
433    * If that fails too, we create the account within the global or separated
434    * namespace depending on rgw_keystone_implicit_tenants. */
435   if (acct_user.tenant.empty()) {
436     const rgw_user tenanted_uid(acct_user.id, acct_user.id);
437
438     if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
439       /* Succeeded. */
440       return;
441     }
442   }
443
444   if (rgw_get_user_info_by_uid(store, acct_user, user_info) < 0) {
445     ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
446     create_account(acct_user, user_info);
447   }
448
449   /* Succeeded if we are here (create_account() hasn't throwed). */
450 }
451
452
453 /* rgw::auth::LocalApplier */
454 /* static declaration */
455 const std::string rgw::auth::LocalApplier::NO_SUBUSER;
456
457 uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
458 {
459   return rgw_perms_from_aclspec_default_strategy(user_info.user_id, aclspec);
460 }
461
462 bool rgw::auth::LocalApplier::is_admin_of(const rgw_user& uid) const
463 {
464   return user_info.admin || user_info.system;
465 }
466
467 bool rgw::auth::LocalApplier::is_owner_of(const rgw_user& uid) const
468 {
469   return uid == user_info.user_id;
470 }
471
472 bool rgw::auth::LocalApplier::is_identity(const idset_t& ids) const {
473   for (auto& id : ids) {
474     if (id.is_wildcard()) {
475       return true;
476     } else if (id.is_tenant() &&
477                id.get_tenant() == user_info.user_id.tenant) {
478       return true;
479     } else if (id.is_user() &&
480                (id.get_tenant() == user_info.user_id.tenant) &&
481                (id.get_id() == user_info.user_id.id)) {
482       return true;
483     }
484   }
485   return false;
486 }
487
488 void rgw::auth::LocalApplier::to_str(std::ostream& out) const {
489   out << "rgw::auth::LocalApplier(acct_user=" << user_info.user_id
490       << ", acct_name=" << user_info.display_name
491       << ", subuser=" << subuser
492       << ", perm_mask=" << get_perm_mask()
493       << ", is_admin=" << static_cast<bool>(user_info.admin) << ")";
494 }
495
496 uint32_t rgw::auth::LocalApplier::get_perm_mask(const std::string& subuser_name,
497                                                 const RGWUserInfo &uinfo) const
498 {
499   if (! subuser_name.empty() && subuser_name != NO_SUBUSER) {
500     const auto iter = uinfo.subusers.find(subuser_name);
501
502     if (iter != std::end(uinfo.subusers)) {
503       return iter->second.perm_mask;
504     } else {
505       /* Subuser specified but not found. */
506       return RGW_PERM_NONE;
507     }
508   } else {
509     /* Due to backward compatibility. */
510     return RGW_PERM_FULL_CONTROL;
511   }
512 }
513
514 void rgw::auth::LocalApplier::load_acct_info(RGWUserInfo& user_info) const /* out */
515 {
516   /* Load the account that belongs to the authenticated identity. An extra call
517    * to RADOS may be safely skipped in this case. */
518   user_info = this->user_info;
519 }
520
521
522 rgw::auth::Engine::result_t
523 rgw::auth::AnonymousEngine::authenticate(const req_state* const s) const
524 {
525   if (! is_applicable(s)) {
526     return result_t::deny(-EPERM);
527   } else {
528     RGWUserInfo user_info;
529     rgw_get_anon_user(user_info);
530
531     auto apl = \
532       apl_factory->create_apl_local(cct, s, user_info,
533                                     rgw::auth::LocalApplier::NO_SUBUSER);
534     return result_t::grant(std::move(apl));
535   }
536 }