]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_rest_user_policy.cc
bump version to 19.2.0-pve1
[ceph.git] / ceph / src / rgw / rgw_rest_user_policy.cc
CommitLineData
11fdf7f2 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
11fdf7f2
TL
3
4#include <errno.h>
5#include <regex>
6
7#include "common/errno.h"
8#include "common/Formatter.h"
9#include "common/ceph_json.h"
10
11#include "include/types.h"
12#include "rgw_string.h"
13
14#include "rgw_common.h"
f51cf556 15#include "rgw_iam_managed_policy.h"
11fdf7f2 16#include "rgw_op.h"
f51cf556 17#include "rgw_process_env.h"
11fdf7f2 18#include "rgw_rest.h"
f51cf556 19#include "rgw_rest_iam.h"
11fdf7f2 20#include "rgw_rest_user_policy.h"
20effc67 21#include "rgw_sal.h"
9f95a23c 22#include "services/svc_zone.h"
11fdf7f2
TL
23
24#define dout_subsys ceph_subsys_rgw
25
f51cf556
TL
26RGWRestUserPolicy::RGWRestUserPolicy(uint64_t action, uint32_t perm)
27 : action(action), perm(perm)
11fdf7f2 28{
11fdf7f2
TL
29}
30
31void RGWRestUserPolicy::send_response()
32{
33 if (op_ret) {
34 set_req_state_err(s, op_ret);
35 }
36 dump_errno(s);
37 end_header(s);
38}
39
f51cf556 40int RGWRestUserPolicy::get_params()
11fdf7f2 41{
f51cf556
TL
42 user_name = s->info.args.get("UserName");
43 if (!validate_iam_user_name(user_name, s->err.message)) {
44 return -EINVAL;
11fdf7f2
TL
45 }
46 return 0;
47}
48
f51cf556 49int RGWRestUserPolicy::init_processing(optional_yield y)
11fdf7f2 50{
f51cf556
TL
51 int r = get_params();
52 if (r < 0) {
53 return r;
11fdf7f2
TL
54 }
55
f51cf556
TL
56 if (const auto* id = std::get_if<rgw_account_id>(&s->owner.id); id) {
57 account_id = *id;
58
59 // look up account user by UserName
60 const std::string& tenant = s->auth.identity->get_tenant();
61 r = driver->load_account_user_by_name(this, y, account_id,
62 tenant, user_name, &user);
63
64 if (r == -ENOENT) {
65 s->err.message = "No such UserName in the account";
66 return -ERR_NO_SUCH_ENTITY;
67 }
68 if (r >= 0) {
69 // user ARN includes account id, path, and display name
70 const RGWUserInfo& info = user->get_info();
71 const std::string resource = string_cat_reserve(info.path, info.display_name);
72 user_arn = rgw::ARN{resource, "user", account_id, true};
73 }
74 } else {
75 // interpret UserName as a uid with optional tenant
76 const auto uid = rgw_user{user_name};
77 // user ARN includes tenant and user id
78 user_arn = rgw::ARN{uid.id, "user", uid.tenant};
79
80 user = driver->get_user(uid);
81 r = user->load_user(this, y);
82 if (r == -ENOENT) {
83 s->err.message = "No such UserName in the tenant";
84 return -ERR_NO_SUCH_ENTITY;
85 }
11fdf7f2
TL
86 }
87
f51cf556 88 return r;
11fdf7f2
TL
89}
90
f51cf556 91int RGWRestUserPolicy::check_caps(const RGWUserCaps& caps)
11fdf7f2 92{
f51cf556 93 return caps.check_cap("user-policy", perm);
11fdf7f2
TL
94}
95
f51cf556 96int RGWRestUserPolicy::verify_permission(optional_yield y)
11fdf7f2 97{
f51cf556
TL
98 if (s->auth.identity->is_anonymous()) {
99 return -EACCES;
100 }
101
102 // admin caps are required for non-account users
103 if (check_caps(s->user->get_caps()) == 0) {
104 return 0;
105 }
106
107 if (! verify_user_permission(this, s, user_arn, action)) {
108 return -EACCES;
109 }
110 return 0;
11fdf7f2
TL
111}
112
f51cf556
TL
113
114RGWPutUserPolicy::RGWPutUserPolicy(const ceph::bufferlist& post_body)
115 : RGWRestUserPolicy(rgw::IAM::iamPutUserPolicy, RGW_CAP_WRITE),
116 post_body(post_body)
11fdf7f2 117{
11fdf7f2
TL
118}
119
120int RGWPutUserPolicy::get_params()
121{
f38dd50b 122 policy_name = s->info.args.get("PolicyName");
f51cf556 123 if (!validate_iam_policy_name(policy_name, s->err.message)) {
11fdf7f2
TL
124 return -EINVAL;
125 }
126
f51cf556
TL
127 policy = s->info.args.get("PolicyDocument");
128 if (policy.empty()) {
129 s->err.message = "Missing required element PolicyDocument";
11fdf7f2
TL
130 return -EINVAL;
131 }
132
f51cf556 133 return RGWRestUserPolicy::get_params();
11fdf7f2
TL
134}
135
f51cf556 136int RGWPutUserPolicy::forward_to_master(optional_yield y, const rgw::SiteConfig& site)
11fdf7f2 137{
f51cf556
TL
138 RGWXMLDecoder::XMLParser parser;
139 if (!parser.init()) {
140 ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
141 return -EINVAL;
11fdf7f2
TL
142 }
143
f51cf556
TL
144 s->info.args.remove("UserName");
145 s->info.args.remove("PolicyName");
146 s->info.args.remove("PolicyDocument");
147 s->info.args.remove("Action");
148 s->info.args.remove("Version");
149
150 int r = forward_iam_request_to_master(this, site, s->user->get_info(),
151 post_body, parser, s->info, y);
152 if (r < 0) {
153 ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << r << dendl;
154 return r;
9f95a23c 155 }
f51cf556
TL
156 return 0;
157}
9f95a23c 158
f51cf556
TL
159void RGWPutUserPolicy::execute(optional_yield y)
160{
161 // validate the policy document
11fdf7f2 162 try {
f51cf556
TL
163 // non-account identity policy is restricted to the current tenant
164 const std::string* policy_tenant = account_id.empty() ?
165 &s->user->get_tenant() : nullptr;
166
1e59de90 167 const rgw::IAM::Policy p(
f51cf556 168 s->cct, policy_tenant, policy,
1e59de90 169 s->cct->_conf.get_val<bool>("rgw_policy_reject_invalid_principals"));
f51cf556 170 } catch (const rgw::IAM::PolicyParseException& e) {
1e59de90
TL
171 ldpp_dout(this, 5) << "failed to parse policy: " << e.what() << dendl;
172 s->err.message = e.what();
11fdf7f2 173 op_ret = -ERR_MALFORMED_DOC;
f51cf556
TL
174 return;
175 }
176
177 const rgw::SiteConfig& site = *s->penv.site;
178 if (!site.is_meta_master()) {
179 op_ret = forward_to_master(y, site);
180 if (op_ret) {
181 return;
182 }
11fdf7f2 183 }
92f5a8d4 184
f51cf556
TL
185 op_ret = retry_raced_user_write(this, y, user.get(),
186 [this, y] {
187 rgw::sal::Attrs& attrs = user->get_attrs();
188 std::map<std::string, std::string> policies;
189 if (auto it = attrs.find(RGW_ATTR_USER_POLICY); it != attrs.end()) try {
190 decode(policies, it->second);
191 } catch (const buffer::error& err) {
192 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
193 return -EIO;
194 }
195
196 policies[policy_name] = policy;
197
198 constexpr unsigned int USER_POLICIES_MAX_NUM = 100;
199 const unsigned int max_num = s->cct->_conf->rgw_user_policies_max_num < 0 ?
200 USER_POLICIES_MAX_NUM : s->cct->_conf->rgw_user_policies_max_num;
201 if (policies.size() > max_num) {
202 ldpp_dout(this, 4) << "IAM user policies has reached the num config: "
203 << max_num << ", cant add another" << dendl;
204 s->err.message =
205 "The number of IAM user policies should not exceed allowed limit "
206 "of " +
207 std::to_string(max_num) + " policies.";
208 return -ERR_LIMIT_EXCEEDED;
209 }
210
211 bufferlist bl;
212 encode(policies, bl);
213 attrs[RGW_ATTR_USER_POLICY] = std::move(bl);
214
215 return user->store_user(s, y, false);
216 });
217
92f5a8d4 218 if (op_ret == 0) {
f51cf556 219 s->formatter->open_object_section_in_ns("PutUserPolicyResponse", RGW_REST_IAM_XMLNS);
92f5a8d4
TL
220 s->formatter->open_object_section("ResponseMetadata");
221 s->formatter->dump_string("RequestId", s->trans_id);
222 s->formatter->close_section();
223 s->formatter->close_section();
224 }
11fdf7f2
TL
225}
226
f51cf556
TL
227
228RGWGetUserPolicy::RGWGetUserPolicy()
229 : RGWRestUserPolicy(rgw::IAM::iamGetUserPolicy, RGW_CAP_READ)
11fdf7f2 230{
11fdf7f2
TL
231}
232
233int RGWGetUserPolicy::get_params()
234{
235 policy_name = s->info.args.get("PolicyName");
f51cf556 236 if (!validate_iam_policy_name(policy_name, s->err.message)) {
11fdf7f2
TL
237 return -EINVAL;
238 }
239
f51cf556 240 return RGWRestUserPolicy::get_params();
11fdf7f2
TL
241}
242
f67539c2 243void RGWGetUserPolicy::execute(optional_yield y)
11fdf7f2 244{
f51cf556
TL
245 std::map<std::string, std::string> policies;
246 if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) {
247 try {
248 decode(policies, it->second);
249 } catch (buffer::error& err) {
250 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
251 op_ret = -EIO;
252 return;
253 }
11fdf7f2
TL
254 }
255
f51cf556
TL
256 auto policy = policies.find(policy_name);
257 if (policy == policies.end()) {
258 s->err.message = "No such PolicyName on the user";
11fdf7f2
TL
259 op_ret = -ERR_NO_SUCH_ENTITY;
260 return;
261 }
262
f51cf556
TL
263 s->formatter->open_object_section_in_ns("GetUserPolicyResponse", RGW_REST_IAM_XMLNS);
264 s->formatter->open_object_section("ResponseMetadata");
265 s->formatter->dump_string("RequestId", s->trans_id);
266 s->formatter->close_section();
267 s->formatter->open_object_section("GetUserPolicyResult");
268 encode_json("PolicyName", policy_name , s->formatter);
269 encode_json("UserName", user_name, s->formatter);
270 encode_json("PolicyDocument", policy->second, s->formatter);
271 s->formatter->close_section();
272 s->formatter->close_section();
273}
274
275
276RGWListUserPolicies::RGWListUserPolicies()
277 : RGWRestUserPolicy(rgw::IAM::iamListUserPolicies, RGW_CAP_READ)
278{
279}
280
281int RGWListUserPolicies::get_params()
282{
283 marker = s->info.args.get("Marker");
284
285 int r = s->info.args.get_int("MaxItems", &max_items, max_items);
286 if (r < 0 || max_items > 1000) {
287 s->err.message = "Invalid value for MaxItems";
288 return -EINVAL;
289 }
290
291 return RGWRestUserPolicy::get_params();
292}
293
294void RGWListUserPolicies::execute(optional_yield y)
295{
296 std::map<std::string, std::string> policies;
297 if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) {
298 try {
299 decode(policies, it->second);
300 } catch (buffer::error& err) {
301 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
302 op_ret = -EIO;
11fdf7f2
TL
303 return;
304 }
305 }
f51cf556
TL
306
307 s->formatter->open_object_section_in_ns("ListUserPoliciesResponse", RGW_REST_IAM_XMLNS);
308 s->formatter->open_object_section("ResponseMetadata");
309 s->formatter->dump_string("RequestId", s->trans_id);
310 s->formatter->close_section();
311 s->formatter->open_object_section("ListUserPoliciesResult");
312 s->formatter->open_array_section("PolicyNames");
313 auto policy = policies.lower_bound(marker);
314 for (; policy != policies.end() && max_items > 0; ++policy, --max_items) {
315 s->formatter->dump_string("member", policy->first);
316 }
317 s->formatter->close_section(); // PolicyNames
318 const bool is_truncated = (policy != policies.end());
319 encode_json("IsTruncated", is_truncated, s->formatter);
320 if (is_truncated) {
321 encode_json("Marker", policy->first, s->formatter);
11fdf7f2 322 }
f51cf556
TL
323 s->formatter->close_section(); // ListUserPoliciesResult
324 s->formatter->close_section(); // ListUserPoliciesResponse
11fdf7f2
TL
325}
326
f51cf556
TL
327
328RGWDeleteUserPolicy::RGWDeleteUserPolicy(const ceph::bufferlist& post_body)
329 : RGWRestUserPolicy(rgw::IAM::iamDeleteUserPolicy, RGW_CAP_WRITE),
330 post_body(post_body)
11fdf7f2 331{
11fdf7f2
TL
332}
333
f51cf556 334int RGWDeleteUserPolicy::get_params()
11fdf7f2 335{
f51cf556
TL
336 policy_name = s->info.args.get("PolicyName");
337 if (!validate_iam_policy_name(policy_name, s->err.message)) {
338 return -EINVAL;
339 }
11fdf7f2 340
f51cf556
TL
341 return RGWRestUserPolicy::get_params();
342}
343
344int RGWDeleteUserPolicy::forward_to_master(optional_yield y, const rgw::SiteConfig& site)
345{
346 RGWXMLDecoder::XMLParser parser;
347 if (!parser.init()) {
348 ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
11fdf7f2
TL
349 return -EINVAL;
350 }
351
f51cf556
TL
352 s->info.args.remove("UserName");
353 s->info.args.remove("PolicyName");
354 s->info.args.remove("Action");
355 s->info.args.remove("Version");
356
357 int r = forward_iam_request_to_master(this, site, s->user->get_info(),
358 post_body, parser, s->info, y);
359 if (r < 0) {
360 ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << r << dendl;
361 return r;
362 }
11fdf7f2
TL
363 return 0;
364}
365
f51cf556 366void RGWDeleteUserPolicy::execute(optional_yield y)
11fdf7f2 367{
f51cf556
TL
368 const rgw::SiteConfig& site = *s->penv.site;
369 if (!site.is_meta_master()) {
370 op_ret = forward_to_master(y, site);
371 if (op_ret) {
372 return;
373 }
374 }
375
376 op_ret = retry_raced_user_write(this, y, user.get(),
377 [this, y, &site] {
378 rgw::sal::Attrs& attrs = user->get_attrs();
379 std::map<std::string, std::string> policies;
380 if (auto it = attrs.find(RGW_ATTR_USER_POLICY); it != attrs.end()) try {
381 decode(policies, it->second);
382 } catch (const buffer::error& err) {
383 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
384 return -EIO;
385 }
386
387 auto policy = policies.find(policy_name);
388 if (policy == policies.end()) {
389 if (!site.is_meta_master()) {
390 return 0; // delete succeeded on the master
391 }
392 s->err.message = "No such PolicyName on the user";
393 return -ERR_NO_SUCH_ENTITY;
394 }
395 policies.erase(policy);
396
397 bufferlist bl;
398 encode(policies, bl);
399 attrs[RGW_ATTR_USER_POLICY] = std::move(bl);
400
401 return user->store_user(s, y, false);
402 });
403
11fdf7f2
TL
404 if (op_ret < 0) {
405 return;
406 }
407
f51cf556
TL
408 s->formatter->open_object_section_in_ns("DeleteUserPoliciesResponse", RGW_REST_IAM_XMLNS);
409 s->formatter->open_object_section("ResponseMetadata");
410 s->formatter->dump_string("RequestId", s->trans_id);
411 s->formatter->close_section();
412 s->formatter->close_section();
413}
414
415
416class RGWAttachUserPolicy_IAM : public RGWRestUserPolicy {
417 bufferlist post_body;
418 std::string policy_arn;
419
420 int get_params() override;
421 int forward_to_master(optional_yield y, const rgw::SiteConfig& site);
422 public:
423 explicit RGWAttachUserPolicy_IAM(const ceph::bufferlist& post_body)
424 : RGWRestUserPolicy(rgw::IAM::iamAttachUserPolicy, RGW_CAP_WRITE),
425 post_body(post_body) {}
426
427 void execute(optional_yield y) override;
428 const char* name() const override { return "attach_user_policy"; }
429 RGWOpType get_type() override { return RGW_OP_ATTACH_USER_POLICY; }
430};
431
432int RGWAttachUserPolicy_IAM::get_params()
433{
434 policy_arn = s->info.args.get("PolicyArn");
435 if (!validate_iam_policy_arn(policy_arn, s->err.message)) {
436 return -EINVAL;
437 }
438
439 return RGWRestUserPolicy::get_params();
440}
441
442int RGWAttachUserPolicy_IAM::forward_to_master(optional_yield y, const rgw::SiteConfig& site)
443{
444 RGWXMLDecoder::XMLParser parser;
445 if (!parser.init()) {
446 ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
447 return -EINVAL;
448 }
449
450 s->info.args.remove("UserName");
451 s->info.args.remove("PolicyArn");
452 s->info.args.remove("Action");
453 s->info.args.remove("Version");
454
455 int r = forward_iam_request_to_master(this, site, s->user->get_info(),
456 post_body, parser, s->info, y);
457 if (r < 0) {
458 ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << r << dendl;
459 return r;
460 }
461 return 0;
462}
463
464void RGWAttachUserPolicy_IAM::execute(optional_yield y)
465{
466 // validate the policy arn
467 try {
468 const auto p = rgw::IAM::get_managed_policy(s->cct, policy_arn);
469 if (!p) {
470 op_ret = ERR_NO_SUCH_ENTITY;
471 s->err.message = "The requested PolicyArn is not recognized";
472 return;
473 }
474 } catch (const rgw::IAM::PolicyParseException& e) {
475 ldpp_dout(this, 5) << "failed to parse policy: " << e.what() << dendl;
476 s->err.message = e.what();
477 op_ret = -ERR_MALFORMED_DOC;
11fdf7f2
TL
478 return;
479 }
480
f51cf556
TL
481 const rgw::SiteConfig& site = *s->penv.site;
482 if (!site.is_meta_master()) {
483 op_ret = forward_to_master(y, site);
484 if (op_ret) {
11fdf7f2
TL
485 return;
486 }
487 }
f51cf556
TL
488
489 op_ret = retry_raced_user_write(this, y, user.get(),
490 [this, y] {
491 rgw::sal::Attrs& attrs = user->get_attrs();
492 rgw::IAM::ManagedPolicies policies;
493 if (auto it = attrs.find(RGW_ATTR_MANAGED_POLICY); it != attrs.end()) try {
494 decode(policies, it->second);
495 } catch (buffer::error& err) {
496 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
497 return -EIO;
498 }
499 policies.arns.insert(policy_arn);
500
501 bufferlist bl;
502 encode(policies, bl);
503 attrs[RGW_ATTR_MANAGED_POLICY] = std::move(bl);
504
505 return user->store_user(this, y, false);
506 });
507
508 if (op_ret == 0) {
509 s->formatter->open_object_section_in_ns("AttachUserPolicyResponse", RGW_REST_IAM_XMLNS);
510 s->formatter->open_object_section("ResponseMetadata");
511 s->formatter->dump_string("RequestId", s->trans_id);
512 s->formatter->close_section();
513 s->formatter->close_section();
11fdf7f2
TL
514 }
515}
516
f51cf556
TL
517
518class RGWRestAttachedUserPolicy : public RGWRestUserPolicy {
519 public:
520 using RGWRestUserPolicy::RGWRestUserPolicy;
521 int init_processing(optional_yield y) override;
522};
523
524int RGWRestAttachedUserPolicy::init_processing(optional_yield y)
11fdf7f2 525{
f51cf556
TL
526 // managed policy is only supported for account users. adding them to
527 // non-account roles would give blanket permissions to all buckets
528 if (!s->auth.identity->get_account()) {
529 s->err.message = "Managed policies are only supported for account users";
530 return -ERR_METHOD_NOT_ALLOWED;
531 }
532
533 return RGWRestUserPolicy::init_processing(y);
11fdf7f2
TL
534}
535
f51cf556
TL
536class RGWDetachUserPolicy_IAM : public RGWRestAttachedUserPolicy {
537 bufferlist post_body;
538 std::string policy_arn;
539
540 int get_params() override;
541 int forward_to_master(optional_yield y, const rgw::SiteConfig& site);
542 public:
543 explicit RGWDetachUserPolicy_IAM(const bufferlist& post_body)
544 : RGWRestAttachedUserPolicy(rgw::IAM::iamDetachUserPolicy, RGW_CAP_WRITE),
545 post_body(post_body) {}
546
547 void execute(optional_yield y) override;
548 const char* name() const override { return "detach_user_policy"; }
549 RGWOpType get_type() override { return RGW_OP_DETACH_USER_POLICY; }
550};
11fdf7f2 551
f51cf556
TL
552int RGWDetachUserPolicy_IAM::get_params()
553{
554 policy_arn = s->info.args.get("PolicyArn");
555 if (!validate_iam_policy_arn(policy_arn, s->err.message)) {
11fdf7f2
TL
556 return -EINVAL;
557 }
558
f51cf556 559 return RGWRestAttachedUserPolicy::get_params();
11fdf7f2
TL
560}
561
f51cf556 562int RGWDetachUserPolicy_IAM::forward_to_master(optional_yield y, const rgw::SiteConfig& site)
11fdf7f2 563{
f51cf556
TL
564 RGWXMLDecoder::XMLParser parser;
565 if (!parser.init()) {
566 ldpp_dout(this, 0) << "ERROR: failed to initialize xml parser" << dendl;
567 return -EINVAL;
11fdf7f2
TL
568 }
569
f51cf556
TL
570 s->info.args.remove("UserName");
571 s->info.args.remove("PolicyArn");
572 s->info.args.remove("Action");
573 s->info.args.remove("Version");
11fdf7f2 574
f51cf556
TL
575 int r = forward_iam_request_to_master(this, site, s->user->get_info(),
576 post_body, parser, s->info, y);
577 if (r < 0) {
578 ldpp_dout(this, 20) << "ERROR: forward_iam_request_to_master failed with error code: " << r << dendl;
579 return r;
20effc67 580 }
f51cf556
TL
581 return 0;
582}
20effc67 583
f51cf556
TL
584void RGWDetachUserPolicy_IAM::execute(optional_yield y)
585{
586 const rgw::SiteConfig& site = *s->penv.site;
587 if (!site.is_meta_master()) {
588 op_ret = forward_to_master(y, site);
589 if (op_ret) {
f67539c2 590 return;
9f95a23c 591 }
11fdf7f2
TL
592 }
593
f51cf556
TL
594 op_ret = retry_raced_user_write(this, y, user.get(),
595 [this, y, &site] {
596 rgw::sal::Attrs& attrs = user->get_attrs();
597 rgw::IAM::ManagedPolicies policies;
598 if (auto it = attrs.find(RGW_ATTR_MANAGED_POLICY); it != attrs.end()) try {
599 decode(policies, it->second);
600 } catch (const buffer::error& err) {
601 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
602 return -EIO;
603 }
604
605 auto i = policies.arns.find(policy_arn);
606 if (i == policies.arns.end()) {
607 if (!site.is_meta_master()) {
608 return 0; // delete succeeded on the master
609 }
610 s->err.message = "No such PolicyArn on the user";
611 return ERR_NO_SUCH_ENTITY;
612 }
613 policies.arns.erase(i);
614
615 bufferlist bl;
616 encode(policies, bl);
617 attrs[RGW_ATTR_MANAGED_POLICY] = std::move(bl);
618
619 return user->store_user(this, y, false);
620 });
621
622 if (op_ret == 0) {
623 s->formatter->open_object_section_in_ns("DetachUserPolicyResponse", RGW_REST_IAM_XMLNS);
624 s->formatter->open_object_section("ResponseMetadata");
625 s->formatter->dump_string("RequestId", s->trans_id);
626 s->formatter->close_section();
627 s->formatter->close_section();
628 }
629}
630
631
632class RGWListAttachedUserPolicies_IAM : public RGWRestAttachedUserPolicy {
633 std::string marker;
634 int max_items = 100;
635 int get_params() override;
636 public:
637 RGWListAttachedUserPolicies_IAM()
638 : RGWRestAttachedUserPolicy(rgw::IAM::iamListAttachedUserPolicies, RGW_CAP_READ)
639 {}
640 void execute(optional_yield y) override;
641 const char* name() const override { return "list_attached_user_policies"; }
642 RGWOpType get_type() override { return RGW_OP_LIST_ATTACHED_USER_POLICIES; }
643};
644
645int RGWListAttachedUserPolicies_IAM::get_params()
646{
647 marker = s->info.args.get("Marker");
648
649 int r = s->info.args.get_int("MaxItems", &max_items, max_items);
650 if (r < 0 || max_items > 1000) {
651 s->err.message = "Invalid value for MaxItems";
652 return -EINVAL;
653 }
654
655 return RGWRestAttachedUserPolicy::get_params();
656}
657
658void RGWListAttachedUserPolicies_IAM::execute(optional_yield y)
659{
660 rgw::IAM::ManagedPolicies policies;
661 const auto& attrs = user->get_attrs();
662 if (auto it = attrs.find(RGW_ATTR_MANAGED_POLICY); it != attrs.end()) {
1e59de90 663 try {
f51cf556 664 decode(policies, it->second);
1e59de90
TL
665 } catch (buffer::error& err) {
666 ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl;
667 op_ret = -EIO;
668 return;
669 }
f51cf556 670 }
11fdf7f2 671
f51cf556
TL
672 s->formatter->open_object_section_in_ns("ListAttachedUserPoliciesResponse", RGW_REST_IAM_XMLNS);
673 s->formatter->open_object_section("ResponseMetadata");
674 s->formatter->dump_string("RequestId", s->trans_id);
675 s->formatter->close_section();
676 s->formatter->open_object_section("ListAttachedUserPoliciesResult");
677 s->formatter->open_array_section("AttachedPolicies");
678 auto policy = policies.arns.lower_bound(marker);
679 for (; policy != policies.arns.end() && max_items > 0; ++policy, --max_items) {
680 s->formatter->open_object_section("member");
681 std::string_view arn = *policy;
682 if (auto p = arn.find('/'); p != arn.npos) {
683 s->formatter->dump_string("PolicyName", arn.substr(p + 1));
11fdf7f2 684 }
f51cf556
TL
685 s->formatter->dump_string("PolicyArn", arn);
686 s->formatter->close_section(); // member
687 }
688 s->formatter->close_section(); // AttachedPolicies
689 const bool is_truncated = (policy != policies.arns.end());
690 encode_json("IsTruncated", is_truncated, s->formatter);
691 if (is_truncated) {
692 encode_json("Marker", *policy, s->formatter);
11fdf7f2 693 }
f51cf556
TL
694 s->formatter->close_section(); // ListAttachedUserPoliciesResult
695 s->formatter->close_section(); // ListAttachedUserPoliciesResponse
696}
697
698
699RGWOp* make_iam_attach_user_policy_op(const ceph::bufferlist& post_body) {
700 return new RGWAttachUserPolicy_IAM(post_body);
701}
702
703RGWOp* make_iam_detach_user_policy_op(const ceph::bufferlist& post_body) {
704 return new RGWDetachUserPolicy_IAM(post_body);
705}
706
707RGWOp* make_iam_list_attached_user_policies_op(const ceph::bufferlist& unused) {
708 return new RGWListAttachedUserPolicies_IAM();
11fdf7f2 709}