]>
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 | #include <array> | |
5 | ||
6 | #include "rgw_common.h" | |
7 | #include "rgw_auth.h" | |
f64942e4 | 8 | #include "rgw_quota.h" |
7c673cae FG |
9 | #include "rgw_user.h" |
10 | #include "rgw_http_client.h" | |
11 | #include "rgw_keystone.h" | |
9f95a23c | 12 | #include "rgw_sal.h" |
7c673cae FG |
13 | |
14 | #include "include/str_list.h" | |
15 | ||
16 | #define dout_context g_ceph_context | |
17 | #define dout_subsys ceph_subsys_rgw | |
18 | ||
19 | ||
20 | namespace rgw { | |
21 | namespace auth { | |
22 | ||
23 | std::unique_ptr<rgw::auth::Identity> | |
9f95a23c TL |
24 | transform_old_authinfo(CephContext* const cct, |
25 | const rgw_user& auth_id, | |
26 | const int perm_mask, | |
27 | const bool is_admin, | |
28 | const uint32_t type) | |
7c673cae FG |
29 | { |
30 | /* This class is not intended for public use. Should be removed altogether | |
31 | * with this function after moving all our APIs to the new authentication | |
32 | * infrastructure. */ | |
33 | class DummyIdentityApplier : public rgw::auth::Identity { | |
34 | CephContext* const cct; | |
35 | ||
36 | /* For this particular case it's OK to use rgw_user structure to convey | |
37 | * the identity info as this was the policy for doing that before the | |
38 | * new auth. */ | |
39 | const rgw_user id; | |
40 | const int perm_mask; | |
41 | const bool is_admin; | |
11fdf7f2 | 42 | const uint32_t type; |
7c673cae FG |
43 | public: |
44 | DummyIdentityApplier(CephContext* const cct, | |
45 | const rgw_user& auth_id, | |
46 | const int perm_mask, | |
11fdf7f2 TL |
47 | const bool is_admin, |
48 | const uint32_t type) | |
7c673cae FG |
49 | : cct(cct), |
50 | id(auth_id), | |
51 | perm_mask(perm_mask), | |
11fdf7f2 TL |
52 | is_admin(is_admin), |
53 | type(type) { | |
7c673cae FG |
54 | } |
55 | ||
11fdf7f2 | 56 | uint32_t get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const override { |
7c673cae FG |
57 | return rgw_perms_from_aclspec_default_strategy(id, aclspec); |
58 | } | |
59 | ||
60 | bool is_admin_of(const rgw_user& acct_id) const override { | |
61 | return is_admin; | |
62 | } | |
63 | ||
64 | bool is_owner_of(const rgw_user& acct_id) const override { | |
65 | return id == acct_id; | |
66 | } | |
67 | ||
31f18b77 FG |
68 | bool is_identity(const idset_t& ids) const override { |
69 | for (auto& p : ids) { | |
70 | if (p.is_wildcard()) { | |
71 | return true; | |
72 | } else if (p.is_tenant() && p.get_tenant() == id.tenant) { | |
73 | return true; | |
74 | } else if (p.is_user() && | |
75 | (p.get_tenant() == id.tenant) && | |
76 | (p.get_id() == id.id)) { | |
77 | return true; | |
78 | } | |
79 | } | |
80 | return false; | |
81 | } | |
82 | ||
7c673cae FG |
83 | uint32_t get_perm_mask() const override { |
84 | return perm_mask; | |
85 | } | |
86 | ||
11fdf7f2 TL |
87 | uint32_t get_identity_type() const override { |
88 | return type; | |
89 | } | |
90 | ||
91 | string get_acct_name() const override { | |
92 | return {}; | |
93 | } | |
94 | ||
f6b5b4d7 TL |
95 | string get_subuser() const override { |
96 | return {}; | |
97 | } | |
98 | ||
7c673cae FG |
99 | void to_str(std::ostream& out) const override { |
100 | out << "RGWDummyIdentityApplier(auth_id=" << id | |
101 | << ", perm_mask=" << perm_mask | |
102 | << ", is_admin=" << is_admin << ")"; | |
103 | } | |
104 | }; | |
105 | ||
106 | return std::unique_ptr<rgw::auth::Identity>( | |
9f95a23c TL |
107 | new DummyIdentityApplier(cct, |
108 | auth_id, | |
109 | perm_mask, | |
110 | is_admin, | |
111 | type)); | |
112 | } | |
113 | ||
114 | std::unique_ptr<rgw::auth::Identity> | |
115 | transform_old_authinfo(const req_state* const s) | |
116 | { | |
117 | return transform_old_authinfo(s->cct, | |
118 | s->user->get_id(), | |
119 | s->perm_mask, | |
7c673cae FG |
120 | /* System user has admin permissions by default - it's supposed to pass |
121 | * through any security check. */ | |
9f95a23c TL |
122 | s->system_request, |
123 | s->user->get_type()); | |
7c673cae FG |
124 | } |
125 | ||
126 | } /* namespace auth */ | |
127 | } /* namespace rgw */ | |
128 | ||
129 | ||
130 | uint32_t rgw_perms_from_aclspec_default_strategy( | |
131 | const rgw_user& uid, | |
132 | const rgw::auth::Identity::aclspec_t& aclspec) | |
133 | { | |
134 | dout(5) << "Searching permissions for uid=" << uid << dendl; | |
135 | ||
136 | const auto iter = aclspec.find(uid.to_str()); | |
137 | if (std::end(aclspec) != iter) { | |
138 | dout(5) << "Found permission: " << iter->second << dendl; | |
139 | return iter->second; | |
140 | } | |
141 | ||
142 | dout(5) << "Permissions for user not found" << dendl; | |
143 | return 0; | |
144 | } | |
145 | ||
146 | ||
147 | static inline const std::string make_spec_item(const std::string& tenant, | |
148 | const std::string& id) | |
149 | { | |
150 | return tenant + ":" + id; | |
151 | } | |
152 | ||
153 | ||
154 | static inline std::pair<bool, rgw::auth::Engine::result_t> | |
155 | strategy_handle_rejected(rgw::auth::Engine::result_t&& engine_result, | |
156 | const rgw::auth::Strategy::Control policy, | |
157 | rgw::auth::Engine::result_t&& strategy_result) | |
158 | { | |
159 | using Control = rgw::auth::Strategy::Control; | |
160 | switch (policy) { | |
161 | case Control::REQUISITE: | |
162 | /* Don't try next. */ | |
163 | return std::make_pair(false, std::move(engine_result)); | |
164 | ||
165 | case Control::SUFFICIENT: | |
166 | /* Don't try next. */ | |
167 | return std::make_pair(false, std::move(engine_result)); | |
168 | ||
169 | case Control::FALLBACK: | |
170 | /* Don't try next. */ | |
171 | return std::make_pair(false, std::move(strategy_result)); | |
172 | ||
173 | default: | |
174 | /* Huh, memory corruption? */ | |
11fdf7f2 | 175 | ceph_abort(); |
7c673cae FG |
176 | } |
177 | } | |
178 | ||
179 | static inline std::pair<bool, rgw::auth::Engine::result_t> | |
180 | strategy_handle_denied(rgw::auth::Engine::result_t&& engine_result, | |
181 | const rgw::auth::Strategy::Control policy, | |
182 | rgw::auth::Engine::result_t&& strategy_result) | |
183 | { | |
184 | using Control = rgw::auth::Strategy::Control; | |
185 | switch (policy) { | |
186 | case Control::REQUISITE: | |
187 | /* Don't try next. */ | |
188 | return std::make_pair(false, std::move(engine_result)); | |
189 | ||
190 | case Control::SUFFICIENT: | |
191 | /* Just try next. */ | |
192 | return std::make_pair(true, std::move(engine_result)); | |
193 | ||
194 | case Control::FALLBACK: | |
195 | return std::make_pair(true, std::move(strategy_result)); | |
196 | ||
197 | default: | |
198 | /* Huh, memory corruption? */ | |
11fdf7f2 | 199 | ceph_abort(); |
7c673cae FG |
200 | } |
201 | } | |
202 | ||
203 | static inline std::pair<bool, rgw::auth::Engine::result_t> | |
204 | strategy_handle_granted(rgw::auth::Engine::result_t&& engine_result, | |
205 | const rgw::auth::Strategy::Control policy, | |
206 | rgw::auth::Engine::result_t&& strategy_result) | |
207 | { | |
208 | using Control = rgw::auth::Strategy::Control; | |
209 | switch (policy) { | |
210 | case Control::REQUISITE: | |
211 | /* Try next. */ | |
212 | return std::make_pair(true, std::move(engine_result)); | |
213 | ||
214 | case Control::SUFFICIENT: | |
215 | /* Don't try next. */ | |
216 | return std::make_pair(false, std::move(engine_result)); | |
217 | ||
218 | case Control::FALLBACK: | |
219 | /* Don't try next. */ | |
220 | return std::make_pair(false, std::move(engine_result)); | |
221 | ||
222 | default: | |
223 | /* Huh, memory corruption? */ | |
11fdf7f2 | 224 | ceph_abort(); |
7c673cae FG |
225 | } |
226 | } | |
227 | ||
228 | rgw::auth::Engine::result_t | |
11fdf7f2 | 229 | rgw::auth::Strategy::authenticate(const DoutPrefixProvider* dpp, const req_state* const s) const |
7c673cae FG |
230 | { |
231 | result_t strategy_result = result_t::deny(); | |
232 | ||
233 | for (const stack_item_t& kv : auth_stack) { | |
234 | const rgw::auth::Engine& engine = kv.first; | |
235 | const auto& policy = kv.second; | |
236 | ||
11fdf7f2 | 237 | ldpp_dout(dpp, 20) << get_name() << ": trying " << engine.get_name() << dendl; |
7c673cae FG |
238 | |
239 | result_t engine_result = result_t::deny(); | |
240 | try { | |
11fdf7f2 | 241 | engine_result = engine.authenticate(dpp, s); |
7c673cae FG |
242 | } catch (const int err) { |
243 | engine_result = result_t::deny(err); | |
244 | } | |
245 | ||
246 | bool try_next = true; | |
247 | switch (engine_result.get_status()) { | |
248 | case result_t::Status::REJECTED: { | |
11fdf7f2 | 249 | ldpp_dout(dpp, 20) << engine.get_name() << " rejected with reason=" |
7c673cae FG |
250 | << engine_result.get_reason() << dendl; |
251 | ||
252 | std::tie(try_next, strategy_result) = \ | |
253 | strategy_handle_rejected(std::move(engine_result), policy, | |
254 | std::move(strategy_result)); | |
255 | break; | |
256 | } | |
257 | case result_t::Status::DENIED: { | |
11fdf7f2 | 258 | ldpp_dout(dpp, 20) << engine.get_name() << " denied with reason=" |
7c673cae FG |
259 | << engine_result.get_reason() << dendl; |
260 | ||
261 | std::tie(try_next, strategy_result) = \ | |
262 | strategy_handle_denied(std::move(engine_result), policy, | |
263 | std::move(strategy_result)); | |
264 | break; | |
265 | } | |
266 | case result_t::Status::GRANTED: { | |
11fdf7f2 | 267 | ldpp_dout(dpp, 20) << engine.get_name() << " granted access" << dendl; |
7c673cae FG |
268 | |
269 | std::tie(try_next, strategy_result) = \ | |
270 | strategy_handle_granted(std::move(engine_result), policy, | |
271 | std::move(strategy_result)); | |
272 | break; | |
273 | } | |
274 | default: { | |
11fdf7f2 | 275 | ceph_abort(); |
7c673cae FG |
276 | } |
277 | } | |
278 | ||
279 | if (! try_next) { | |
280 | break; | |
281 | } | |
282 | } | |
283 | ||
284 | return strategy_result; | |
285 | } | |
286 | ||
31f18b77 | 287 | int |
11fdf7f2 | 288 | rgw::auth::Strategy::apply(const DoutPrefixProvider *dpp, const rgw::auth::Strategy& auth_strategy, |
31f18b77 FG |
289 | req_state* const s) noexcept |
290 | { | |
291 | try { | |
11fdf7f2 | 292 | auto result = auth_strategy.authenticate(dpp, s); |
31f18b77 FG |
293 | if (result.get_status() != decltype(result)::Status::GRANTED) { |
294 | /* Access denied is acknowledged by returning a std::unique_ptr with | |
295 | * nullptr inside. */ | |
11fdf7f2 | 296 | ldpp_dout(dpp, 5) << "Failed the auth strategy, reason=" |
31f18b77 FG |
297 | << result.get_reason() << dendl; |
298 | return result.get_reason(); | |
299 | } | |
300 | ||
301 | try { | |
302 | rgw::auth::IdentityApplier::aplptr_t applier = result.get_applier(); | |
303 | rgw::auth::Completer::cmplptr_t completer = result.get_completer(); | |
304 | ||
305 | /* Account used by a given RGWOp is decoupled from identity employed | |
306 | * in the authorization phase (RGWOp::verify_permissions). */ | |
9f95a23c | 307 | applier->load_acct_info(dpp, s->user->get_info()); |
31f18b77 FG |
308 | s->perm_mask = applier->get_perm_mask(); |
309 | ||
11fdf7f2 | 310 | /* This is the single place where we pass req_state as a pointer |
31f18b77 FG |
311 | * to non-const and thus its modification is allowed. In the time |
312 | * of writing only RGWTempURLEngine needed that feature. */ | |
11fdf7f2 | 313 | applier->modify_request_state(dpp, s); |
31f18b77 | 314 | if (completer) { |
11fdf7f2 | 315 | completer->modify_request_state(dpp, s); |
31f18b77 FG |
316 | } |
317 | ||
318 | s->auth.identity = std::move(applier); | |
319 | s->auth.completer = std::move(completer); | |
320 | ||
321 | return 0; | |
322 | } catch (const int err) { | |
11fdf7f2 | 323 | ldpp_dout(dpp, 5) << "applier throwed err=" << err << dendl; |
31f18b77 FG |
324 | return err; |
325 | } | |
326 | } catch (const int err) { | |
11fdf7f2 | 327 | ldpp_dout(dpp, 5) << "auth engine throwed err=" << err << dendl; |
31f18b77 FG |
328 | return err; |
329 | } | |
330 | ||
331 | /* We never should be here. */ | |
332 | return -EPERM; | |
333 | } | |
334 | ||
7c673cae FG |
335 | void |
336 | rgw::auth::Strategy::add_engine(const Control ctrl_flag, | |
337 | const Engine& engine) noexcept | |
338 | { | |
339 | auth_stack.push_back(std::make_pair(std::cref(engine), ctrl_flag)); | |
340 | } | |
341 | ||
11fdf7f2 TL |
342 | void rgw::auth::WebIdentityApplier::to_str(std::ostream& out) const |
343 | { | |
344 | out << "rgw::auth::WebIdentityApplier(sub =" << token_claims.sub | |
345 | << ", user_name=" << token_claims.user_name | |
346 | << ", aud =" << token_claims.aud | |
347 | << ", provider_id =" << token_claims.iss << ")"; | |
348 | } | |
349 | ||
350 | string rgw::auth::WebIdentityApplier::get_idp_url() const | |
351 | { | |
352 | string idp_url = token_claims.iss; | |
353 | auto pos = idp_url.find("http://"); | |
354 | if (pos == std::string::npos) { | |
355 | pos = idp_url.find("https://"); | |
356 | if (pos != std::string::npos) { | |
357 | idp_url.erase(pos, 8); | |
358 | } | |
359 | } else { | |
360 | idp_url.erase(pos, 7); | |
361 | } | |
362 | return idp_url; | |
363 | } | |
364 | ||
365 | void rgw::auth::WebIdentityApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const | |
366 | { | |
367 | s->info.args.append("sub", token_claims.sub); | |
368 | s->info.args.append("aud", token_claims.aud); | |
369 | s->info.args.append("provider_id", token_claims.iss); | |
370 | ||
371 | string idp_url = get_idp_url(); | |
372 | string condition = idp_url + ":app_id"; | |
373 | s->env.emplace(condition, token_claims.aud); | |
374 | } | |
375 | ||
376 | bool rgw::auth::WebIdentityApplier::is_identity(const idset_t& ids) const | |
377 | { | |
378 | if (ids.size() > 1) { | |
379 | return false; | |
380 | } | |
381 | ||
382 | for (auto id : ids) { | |
383 | string idp_url = get_idp_url(); | |
384 | if (id.is_oidc_provider() && id.get_idp_url() == idp_url) { | |
385 | return true; | |
386 | } | |
387 | } | |
388 | return false; | |
389 | } | |
7c673cae FG |
390 | |
391 | /* rgw::auth::RemoteAuthApplier */ | |
11fdf7f2 | 392 | uint32_t rgw::auth::RemoteApplier::get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const |
7c673cae FG |
393 | { |
394 | uint32_t perm = 0; | |
395 | ||
396 | /* For backward compatibility with ACLOwner. */ | |
397 | perm |= rgw_perms_from_aclspec_default_strategy(info.acct_user, | |
398 | aclspec); | |
399 | ||
400 | /* We also need to cover cases where rgw_keystone_implicit_tenants | |
401 | * was enabled. */ | |
402 | if (info.acct_user.tenant.empty()) { | |
403 | const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id); | |
404 | ||
405 | perm |= rgw_perms_from_aclspec_default_strategy(tenanted_acct_user, | |
406 | aclspec); | |
407 | } | |
408 | ||
409 | /* Now it's a time for invoking additional strategy that was supplied by | |
410 | * a specific auth engine. */ | |
411 | if (extra_acl_strategy) { | |
412 | perm |= extra_acl_strategy(aclspec); | |
413 | } | |
414 | ||
11fdf7f2 | 415 | ldpp_dout(dpp, 20) << "from ACL got perm=" << perm << dendl; |
7c673cae FG |
416 | return perm; |
417 | } | |
418 | ||
419 | bool rgw::auth::RemoteApplier::is_admin_of(const rgw_user& uid) const | |
420 | { | |
421 | return info.is_admin; | |
422 | } | |
423 | ||
424 | bool rgw::auth::RemoteApplier::is_owner_of(const rgw_user& uid) const | |
425 | { | |
426 | if (info.acct_user.tenant.empty()) { | |
427 | const rgw_user tenanted_acct_user(info.acct_user.id, info.acct_user.id); | |
428 | ||
429 | if (tenanted_acct_user == uid) { | |
430 | return true; | |
431 | } | |
432 | } | |
433 | ||
434 | return info.acct_user == uid; | |
435 | } | |
436 | ||
31f18b77 FG |
437 | bool rgw::auth::RemoteApplier::is_identity(const idset_t& ids) const { |
438 | for (auto& id : ids) { | |
439 | if (id.is_wildcard()) { | |
440 | return true; | |
441 | ||
442 | // We also need to cover cases where rgw_keystone_implicit_tenants | |
443 | // was enabled. */ | |
444 | } else if (id.is_tenant() && | |
445 | (info.acct_user.tenant.empty() ? | |
446 | info.acct_user.id : | |
447 | info.acct_user.tenant) == id.get_tenant()) { | |
448 | return true; | |
449 | } else if (id.is_user() && | |
450 | info.acct_user.id == id.get_id() && | |
451 | (info.acct_user.tenant.empty() ? | |
452 | info.acct_user.id : | |
453 | info.acct_user.tenant) == id.get_tenant()) { | |
454 | return true; | |
455 | } | |
456 | } | |
457 | return false; | |
458 | } | |
459 | ||
7c673cae FG |
460 | void rgw::auth::RemoteApplier::to_str(std::ostream& out) const |
461 | { | |
462 | out << "rgw::auth::RemoteApplier(acct_user=" << info.acct_user | |
463 | << ", acct_name=" << info.acct_name | |
464 | << ", perm_mask=" << info.perm_mask | |
465 | << ", is_admin=" << info.is_admin << ")"; | |
466 | } | |
467 | ||
9f95a23c TL |
468 | void rgw::auth::ImplicitTenants::recompute_value(const ConfigProxy& c) |
469 | { | |
470 | std::string s = c.get_val<std::string>("rgw_keystone_implicit_tenants"); | |
471 | int v = 0; | |
472 | if (boost::iequals(s, "both") | |
473 | || boost::iequals(s, "true") | |
474 | || boost::iequals(s, "1")) { | |
475 | v = IMPLICIT_TENANTS_S3|IMPLICIT_TENANTS_SWIFT; | |
476 | } else if (boost::iequals(s, "0") | |
477 | || boost::iequals(s, "none") | |
478 | || boost::iequals(s, "false")) { | |
479 | v = 0; | |
480 | } else if (boost::iequals(s, "s3")) { | |
481 | v = IMPLICIT_TENANTS_S3; | |
482 | } else if (boost::iequals(s, "swift")) { | |
483 | v = IMPLICIT_TENANTS_SWIFT; | |
484 | } else { /* "" (and anything else) */ | |
485 | v = IMPLICIT_TENANTS_BAD; | |
486 | // assert(0); | |
487 | } | |
488 | saved = v; | |
489 | } | |
490 | ||
491 | const char **rgw::auth::ImplicitTenants::get_tracked_conf_keys() const | |
492 | { | |
493 | static const char *keys[] = { | |
494 | "rgw_keystone_implicit_tenants", | |
495 | nullptr }; | |
496 | return keys; | |
497 | } | |
498 | ||
499 | void rgw::auth::ImplicitTenants::handle_conf_change(const ConfigProxy& c, | |
500 | const std::set <std::string> &changed) | |
501 | { | |
502 | if (changed.count("rgw_keystone_implicit_tenants")) { | |
503 | recompute_value(c); | |
504 | } | |
505 | } | |
506 | ||
11fdf7f2 TL |
507 | void rgw::auth::RemoteApplier::create_account(const DoutPrefixProvider* dpp, |
508 | const rgw_user& acct_user, | |
9f95a23c | 509 | bool implicit_tenant, |
7c673cae FG |
510 | RGWUserInfo& user_info) const /* out */ |
511 | { | |
512 | rgw_user new_acct_user = acct_user; | |
513 | ||
514 | if (info.acct_type) { | |
515 | //ldap/keystone for s3 users | |
516 | user_info.type = info.acct_type; | |
517 | } | |
518 | ||
519 | /* An upper layer may enforce creating new accounts within their own | |
520 | * tenants. */ | |
9f95a23c | 521 | if (new_acct_user.tenant.empty() && implicit_tenant) { |
7c673cae FG |
522 | new_acct_user.tenant = new_acct_user.id; |
523 | } | |
524 | ||
525 | user_info.user_id = new_acct_user; | |
526 | user_info.display_name = info.acct_name; | |
527 | ||
f6b5b4d7 TL |
528 | user_info.max_buckets = |
529 | cct->_conf.get_val<int64_t>("rgw_user_max_buckets"); | |
11fdf7f2 TL |
530 | rgw_apply_default_bucket_quota(user_info.bucket_quota, cct->_conf); |
531 | rgw_apply_default_user_quota(user_info.user_quota, cct->_conf); | |
f64942e4 | 532 | |
9f95a23c TL |
533 | int ret = ctl->user->store_info(user_info, null_yield, |
534 | RGWUserCtl::PutParams().set_exclusive(true)); | |
7c673cae | 535 | if (ret < 0) { |
11fdf7f2 | 536 | ldpp_dout(dpp, 0) << "ERROR: failed to store new user info: user=" |
7c673cae FG |
537 | << user_info.user_id << " ret=" << ret << dendl; |
538 | throw ret; | |
539 | } | |
540 | } | |
541 | ||
542 | /* TODO(rzarzynski): we need to handle display_name changes. */ | |
11fdf7f2 | 543 | void rgw::auth::RemoteApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const /* out */ |
7c673cae FG |
544 | { |
545 | /* It's supposed that RGWRemoteAuthApplier tries to load account info | |
546 | * that belongs to the authenticated identity. Another policy may be | |
547 | * applied by using a RGWThirdPartyAccountAuthApplier decorator. */ | |
548 | const rgw_user& acct_user = info.acct_user; | |
9f95a23c TL |
549 | auto implicit_value = implicit_tenant_context.get_value(); |
550 | bool implicit_tenant = implicit_value.implicit_tenants_for_(implicit_tenant_bit); | |
551 | bool split_mode = implicit_value.is_split_mode(); | |
7c673cae FG |
552 | |
553 | /* Normally, empty "tenant" field of acct_user means the authenticated | |
554 | * identity has the legacy, global tenant. However, due to inclusion | |
555 | * of multi-tenancy, we got some special compatibility kludge for remote | |
556 | * backends like Keystone. | |
557 | * If the global tenant is the requested one, we try the same tenant as | |
558 | * the user name first. If that RGWUserInfo exists, we use it. This way, | |
559 | * migrated OpenStack users can get their namespaced containers and nobody's | |
560 | * the wiser. | |
561 | * If that fails, we look up in the requested (possibly empty) tenant. | |
562 | * If that fails too, we create the account within the global or separated | |
9f95a23c TL |
563 | * namespace depending on rgw_keystone_implicit_tenants. |
564 | * For compatibility with previous versions of ceph, it is possible | |
565 | * to enable implicit_tenants for only s3 or only swift. | |
566 | * in this mode ("split_mode"), we must constrain the id lookups to | |
567 | * only use the identifier space that would be used if the id were | |
568 | * to be created. */ | |
569 | ||
570 | if (split_mode && !implicit_tenant) | |
571 | ; /* suppress lookup for id used by "other" protocol */ | |
572 | else if (acct_user.tenant.empty()) { | |
7c673cae FG |
573 | const rgw_user tenanted_uid(acct_user.id, acct_user.id); |
574 | ||
9f95a23c | 575 | if (ctl->user->get_info_by_uid(tenanted_uid, &user_info, null_yield) >= 0) { |
7c673cae FG |
576 | /* Succeeded. */ |
577 | return; | |
578 | } | |
579 | } | |
580 | ||
9f95a23c TL |
581 | if (split_mode && implicit_tenant) |
582 | ; /* suppress lookup for id used by "other" protocol */ | |
583 | else if (ctl->user->get_info_by_uid(acct_user, &user_info, null_yield) >= 0) { | |
584 | /* Succeeded. */ | |
585 | return; | |
7c673cae FG |
586 | } |
587 | ||
9f95a23c TL |
588 | ldpp_dout(dpp, 0) << "NOTICE: couldn't map swift user " << acct_user << dendl; |
589 | create_account(dpp, acct_user, implicit_tenant, user_info); | |
590 | ||
7c673cae FG |
591 | /* Succeeded if we are here (create_account() hasn't throwed). */ |
592 | } | |
593 | ||
7c673cae FG |
594 | /* rgw::auth::LocalApplier */ |
595 | /* static declaration */ | |
596 | const std::string rgw::auth::LocalApplier::NO_SUBUSER; | |
597 | ||
11fdf7f2 | 598 | uint32_t rgw::auth::LocalApplier::get_perms_from_aclspec(const DoutPrefixProvider* dpp, const aclspec_t& aclspec) const |
7c673cae FG |
599 | { |
600 | return rgw_perms_from_aclspec_default_strategy(user_info.user_id, aclspec); | |
601 | } | |
602 | ||
603 | bool rgw::auth::LocalApplier::is_admin_of(const rgw_user& uid) const | |
604 | { | |
605 | return user_info.admin || user_info.system; | |
606 | } | |
607 | ||
608 | bool rgw::auth::LocalApplier::is_owner_of(const rgw_user& uid) const | |
609 | { | |
610 | return uid == user_info.user_id; | |
611 | } | |
612 | ||
31f18b77 FG |
613 | bool rgw::auth::LocalApplier::is_identity(const idset_t& ids) const { |
614 | for (auto& id : ids) { | |
615 | if (id.is_wildcard()) { | |
616 | return true; | |
617 | } else if (id.is_tenant() && | |
618 | id.get_tenant() == user_info.user_id.tenant) { | |
619 | return true; | |
620 | } else if (id.is_user() && | |
9f95a23c TL |
621 | (id.get_tenant() == user_info.user_id.tenant)) { |
622 | if (id.get_id() == user_info.user_id.id) { | |
623 | return true; | |
624 | } | |
f6b5b4d7 TL |
625 | std::string wildcard_subuser = user_info.user_id.id; |
626 | wildcard_subuser.append(":*"); | |
627 | if (wildcard_subuser == id.get_id()) { | |
628 | return true; | |
629 | } else if (subuser != NO_SUBUSER) { | |
9f95a23c TL |
630 | std::string user = user_info.user_id.id; |
631 | user.append(":"); | |
632 | user.append(subuser); | |
633 | if (user == id.get_id()) { | |
634 | return true; | |
635 | } | |
636 | } | |
31f18b77 FG |
637 | } |
638 | } | |
639 | return false; | |
640 | } | |
641 | ||
642 | void rgw::auth::LocalApplier::to_str(std::ostream& out) const { | |
7c673cae FG |
643 | out << "rgw::auth::LocalApplier(acct_user=" << user_info.user_id |
644 | << ", acct_name=" << user_info.display_name | |
645 | << ", subuser=" << subuser | |
646 | << ", perm_mask=" << get_perm_mask() | |
647 | << ", is_admin=" << static_cast<bool>(user_info.admin) << ")"; | |
648 | } | |
649 | ||
650 | uint32_t rgw::auth::LocalApplier::get_perm_mask(const std::string& subuser_name, | |
651 | const RGWUserInfo &uinfo) const | |
652 | { | |
653 | if (! subuser_name.empty() && subuser_name != NO_SUBUSER) { | |
654 | const auto iter = uinfo.subusers.find(subuser_name); | |
655 | ||
656 | if (iter != std::end(uinfo.subusers)) { | |
657 | return iter->second.perm_mask; | |
658 | } else { | |
659 | /* Subuser specified but not found. */ | |
660 | return RGW_PERM_NONE; | |
661 | } | |
662 | } else { | |
663 | /* Due to backward compatibility. */ | |
664 | return RGW_PERM_FULL_CONTROL; | |
665 | } | |
666 | } | |
667 | ||
11fdf7f2 | 668 | void rgw::auth::LocalApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const /* out */ |
7c673cae FG |
669 | { |
670 | /* Load the account that belongs to the authenticated identity. An extra call | |
671 | * to RADOS may be safely skipped in this case. */ | |
672 | user_info = this->user_info; | |
673 | } | |
674 | ||
11fdf7f2 TL |
675 | void rgw::auth::RoleApplier::to_str(std::ostream& out) const { |
676 | out << "rgw::auth::LocalApplier(role name =" << role_name; | |
677 | for (auto policy : role_policies) { | |
678 | out << ", role policy =" << policy; | |
679 | } | |
680 | out << ")"; | |
681 | } | |
682 | ||
683 | bool rgw::auth::RoleApplier::is_identity(const idset_t& ids) const { | |
684 | for (auto& p : ids) { | |
685 | string name; | |
686 | string tenant = p.get_tenant(); | |
687 | if (tenant.empty()) { | |
688 | name = p.get_id(); | |
689 | } else { | |
690 | name = tenant + "$" + p.get_id(); | |
691 | } | |
692 | if (p.is_wildcard()) { | |
693 | return true; | |
694 | } else if (p.is_role() && name == role_name) { | |
695 | return true; | |
696 | } | |
697 | } | |
698 | return false; | |
699 | } | |
700 | ||
701 | void rgw::auth::RoleApplier::load_acct_info(const DoutPrefixProvider* dpp, RGWUserInfo& user_info) const /* out */ | |
702 | { | |
703 | /* Load the user id */ | |
704 | user_info.user_id = this->user_id; | |
705 | } | |
706 | ||
707 | void rgw::auth::RoleApplier::modify_request_state(const DoutPrefixProvider *dpp, req_state* s) const | |
708 | { | |
709 | for (auto it : role_policies) { | |
710 | try { | |
711 | bufferlist bl = bufferlist::static_from_string(it); | |
9f95a23c | 712 | const rgw::IAM::Policy p(s->cct, s->user->get_tenant(), bl); |
11fdf7f2 TL |
713 | s->iam_user_policies.push_back(std::move(p)); |
714 | } catch (rgw::IAM::PolicyParseException& e) { | |
715 | //Control shouldn't reach here as the policy has already been | |
716 | //verified earlier | |
717 | ldpp_dout(dpp, 20) << "failed to parse policy: " << e.what() << dendl; | |
718 | } | |
719 | } | |
720 | } | |
7c673cae FG |
721 | |
722 | rgw::auth::Engine::result_t | |
11fdf7f2 | 723 | rgw::auth::AnonymousEngine::authenticate(const DoutPrefixProvider* dpp, const req_state* const s) const |
7c673cae FG |
724 | { |
725 | if (! is_applicable(s)) { | |
31f18b77 | 726 | return result_t::deny(-EPERM); |
7c673cae FG |
727 | } else { |
728 | RGWUserInfo user_info; | |
729 | rgw_get_anon_user(user_info); | |
730 | ||
d2e6a577 FG |
731 | auto apl = \ |
732 | apl_factory->create_apl_local(cct, s, user_info, | |
11fdf7f2 TL |
733 | rgw::auth::LocalApplier::NO_SUBUSER, |
734 | boost::none); | |
7c673cae FG |
735 | return result_t::grant(std::move(apl)); |
736 | } | |
737 | } |