]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_auth.cc
update sources to 12.2.7
[ceph.git] / ceph / src / rgw / rgw_auth.cc
CommitLineData
7c673cae
FG
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
18namespace rgw {
19namespace auth {
20
21std::unique_ptr<rgw::auth::Identity>
22transform_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
31f18b77
FG
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
7c673cae
FG
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
98uint32_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
115static inline const std::string make_spec_item(const std::string& tenant,
116 const std::string& id)
117{
118 return tenant + ":" + id;
119}
120
121
122static inline std::pair<bool, rgw::auth::Engine::result_t>
123strategy_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
147static inline std::pair<bool, rgw::auth::Engine::result_t>
148strategy_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
171static inline std::pair<bool, rgw::auth::Engine::result_t>
172strategy_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
196rgw::auth::Engine::result_t
197rgw::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
31f18b77
FG
255int
256rgw::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
7c673cae
FG
303void
304rgw::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 */
312uint32_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
339bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user& uid) const
340{
341 return info.is_admin;
342}
343
344bool 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
31f18b77
FG
357bool 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
7c673cae
FG
380void 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
28e407b8
AA
388void rgw::auth::ImplicitTenants::recompute_value(const md_config_t *c)
389{
390 std::string s = c->get_val<std::string>("rgw_keystone_implicit_tenants");
391 int v = 0;
392 if (boost::iequals(s, "both")
393 || boost::iequals(s, "true")
394 || boost::iequals(s, "1")) {
395 v = IMPLICIT_TENANTS_S3|IMPLICIT_TENANTS_SWIFT;
396 } else if (boost::iequals(s, "0")
397 || boost::iequals(s, "none")
398 || boost::iequals(s, "false")) {
399 v = 0;
400 } else if (boost::iequals(s, "s3")) {
401 v = IMPLICIT_TENANTS_S3;
402 } else if (boost::iequals(s, "swift")) {
403 v = IMPLICIT_TENANTS_SWIFT;
404 } else { /* "" (and anything else) */
405 v = IMPLICIT_TENANTS_BAD;
406 // assert(0);
407 }
408 saved = v;
409}
410
411const char **rgw::auth::ImplicitTenants::get_tracked_conf_keys() const
412{
413 static const char *keys[] = {
414 "rgw_keystone_implicit_tenants",
415 NULL };
416 return keys;
417}
418
419void rgw::auth::ImplicitTenants::handle_conf_change(const struct md_config_t *c,
420 const std::set <std::string> &changed)
421{
422 if (changed.count("rgw_keystone_implicit_tenants")) {
423 recompute_value(c);
424 }
425}
426
7c673cae 427void rgw::auth::RemoteApplier::create_account(const rgw_user& acct_user,
28e407b8 428 bool implicit_tenant,
7c673cae
FG
429 RGWUserInfo& user_info) const /* out */
430{
431 rgw_user new_acct_user = acct_user;
432
433 if (info.acct_type) {
434 //ldap/keystone for s3 users
435 user_info.type = info.acct_type;
436 }
437
438 /* An upper layer may enforce creating new accounts within their own
439 * tenants. */
28e407b8 440 if (new_acct_user.tenant.empty() && implicit_tenant) {
7c673cae
FG
441 new_acct_user.tenant = new_acct_user.id;
442 }
443
444 user_info.user_id = new_acct_user;
445 user_info.display_name = info.acct_name;
446
447 int ret = rgw_store_user_info(store, user_info, nullptr, nullptr,
448 real_time(), true);
449 if (ret < 0) {
450 ldout(cct, 0) << "ERROR: failed to store new user info: user="
451 << user_info.user_id << " ret=" << ret << dendl;
452 throw ret;
453 }
454}
455
456/* TODO(rzarzynski): we need to handle display_name changes. */
457void rgw::auth::RemoteApplier::load_acct_info(RGWUserInfo& user_info) const /* out */
458{
459 /* It's supposed that RGWRemoteAuthApplier tries to load account info
460 * that belongs to the authenticated identity. Another policy may be
461 * applied by using a RGWThirdPartyAccountAuthApplier decorator. */
462 const rgw_user& acct_user = info.acct_user;
28e407b8
AA
463 auto implicit_value = implicit_tenant_context.get_value();
464 bool implicit_tenant = implicit_value.implicit_tenants_for_(implicit_tenant_bit);
465 bool split_mode = implicit_value.is_split_mode();
7c673cae
FG
466
467 /* Normally, empty "tenant" field of acct_user means the authenticated
468 * identity has the legacy, global tenant. However, due to inclusion
469 * of multi-tenancy, we got some special compatibility kludge for remote
470 * backends like Keystone.
471 * If the global tenant is the requested one, we try the same tenant as
472 * the user name first. If that RGWUserInfo exists, we use it. This way,
473 * migrated OpenStack users can get their namespaced containers and nobody's
474 * the wiser.
475 * If that fails, we look up in the requested (possibly empty) tenant.
476 * If that fails too, we create the account within the global or separated
28e407b8
AA
477 * namespace depending on rgw_keystone_implicit_tenants.
478 * For compatibility with previous versions of ceph, it is possible
479 * to enable implicit_tenants for only s3 or only swift.
480 * in this mode ("split_mode"), we must constrain the id lookups to
481 * only use the identifier space that would be used if the id were
482 * to be created. */
483
484 if (split_mode && !implicit_tenant)
485 ; /* suppress lookup for id used by "other" protocol */
486 else if (acct_user.tenant.empty()) {
7c673cae
FG
487 const rgw_user tenanted_uid(acct_user.id, acct_user.id);
488
489 if (rgw_get_user_info_by_uid(store, tenanted_uid, user_info) >= 0) {
490 /* Succeeded. */
491 return;
492 }
493 }
494
28e407b8
AA
495 if (split_mode && implicit_tenant)
496 ; /* suppress lookup for id used by "other" protocol */
497 else if (rgw_get_user_info_by_uid(store, acct_user, user_info) >= 0) {
498 /* Succeeded. */
499 return;
7c673cae
FG
500 }
501
28e407b8
AA
502 ldout(cct, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl;
503 create_account(acct_user, implicit_tenant, user_info);
504
7c673cae
FG
505 /* Succeeded if we are here (create_account() hasn't throwed). */
506}
507
508
509/* rgw::auth::LocalApplier */
510/* static declaration */
511const std::string rgw::auth::LocalApplier::NO_SUBUSER;
512
513uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const aclspec_t& aclspec) const
514{
515 return rgw_perms_from_aclspec_default_strategy(user_info.user_id, aclspec);
516}
517
518bool rgw::auth::LocalApplier::is_admin_of(const rgw_user& uid) const
519{
520 return user_info.admin || user_info.system;
521}
522
523bool rgw::auth::LocalApplier::is_owner_of(const rgw_user& uid) const
524{
525 return uid == user_info.user_id;
526}
527
31f18b77
FG
528bool rgw::auth::LocalApplier::is_identity(const idset_t& ids) const {
529 for (auto& id : ids) {
530 if (id.is_wildcard()) {
531 return true;
532 } else if (id.is_tenant() &&
533 id.get_tenant() == user_info.user_id.tenant) {
534 return true;
535 } else if (id.is_user() &&
536 (id.get_tenant() == user_info.user_id.tenant) &&
537 (id.get_id() == user_info.user_id.id)) {
538 return true;
539 }
540 }
541 return false;
542}
543
544void rgw::auth::LocalApplier::to_str(std::ostream& out) const {
7c673cae
FG
545 out << "rgw::auth::LocalApplier(acct_user=" << user_info.user_id
546 << ", acct_name=" << user_info.display_name
547 << ", subuser=" << subuser
548 << ", perm_mask=" << get_perm_mask()
549 << ", is_admin=" << static_cast<bool>(user_info.admin) << ")";
550}
551
552uint32_t rgw::auth::LocalApplier::get_perm_mask(const std::string& subuser_name,
553 const RGWUserInfo &uinfo) const
554{
555 if (! subuser_name.empty() && subuser_name != NO_SUBUSER) {
556 const auto iter = uinfo.subusers.find(subuser_name);
557
558 if (iter != std::end(uinfo.subusers)) {
559 return iter->second.perm_mask;
560 } else {
561 /* Subuser specified but not found. */
562 return RGW_PERM_NONE;
563 }
564 } else {
565 /* Due to backward compatibility. */
566 return RGW_PERM_FULL_CONTROL;
567 }
568}
569
570void rgw::auth::LocalApplier::load_acct_info(RGWUserInfo& user_info) const /* out */
571{
572 /* Load the account that belongs to the authenticated identity. An extra call
573 * to RADOS may be safely skipped in this case. */
574 user_info = this->user_info;
575}
576
577
578rgw::auth::Engine::result_t
579rgw::auth::AnonymousEngine::authenticate(const req_state* const s) const
580{
581 if (! is_applicable(s)) {
31f18b77 582 return result_t::deny(-EPERM);
7c673cae
FG
583 } else {
584 RGWUserInfo user_info;
585 rgw_get_anon_user(user_info);
586
d2e6a577
FG
587 auto apl = \
588 apl_factory->create_apl_local(cct, s, user_info,
589 rgw::auth::LocalApplier::NO_SUBUSER);
7c673cae
FG
590 return result_t::grant(std::move(apl));
591 }
592}