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