1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "common/ceph_json.h"
8 #include "rgw_rest_user.h"
10 #include "include/str_list.h"
11 #include "include/assert.h"
13 #define dout_subsys ceph_subsys_rgw
15 class RGWOp_User_Info : public RGWRESTOp {
20 int check_caps(RGWUserCaps& caps) override {
21 return caps.check_cap("users", RGW_CAP_READ);
24 void execute() override;
26 const string name() override { return "get_user_info"; }
29 void RGWOp_User_Info::execute()
31 RGWUserAdminOpState op_state;
37 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
39 // if uid was not supplied in rest argument, error out now, otherwise we'll
40 // end up initializing anonymous user, for which keys.init will eventually
47 rgw_user uid(uid_str);
49 RESTArgs::get_bool(s, "stats", false, &fetch_stats);
51 RESTArgs::get_bool(s, "sync", false, &sync_stats);
53 op_state.set_user_id(uid);
54 op_state.set_fetch_stats(fetch_stats);
55 op_state.set_sync_stats(sync_stats);
57 http_ret = RGWUserAdminOp_User::info(store, op_state, flusher);
60 class RGWOp_User_Create : public RGWRESTOp {
63 RGWOp_User_Create() {}
65 int check_caps(RGWUserCaps& caps) override {
66 return caps.check_cap("users", RGW_CAP_WRITE);
69 void execute() override;
71 const string name() override { return "create_user"; }
74 void RGWOp_User_Create::execute()
77 std::string display_name;
79 std::string access_key;
80 std::string secret_key;
81 std::string key_type_str;
83 std::string tenant_name;
91 int32_t default_max_buckets = s->cct->_conf->rgw_user_max_buckets;
93 RGWUserAdminOpState op_state;
95 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
96 rgw_user uid(uid_str);
98 RESTArgs::get_string(s, "display-name", display_name, &display_name);
99 RESTArgs::get_string(s, "email", email, &email);
100 RESTArgs::get_string(s, "access-key", access_key, &access_key);
101 RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
102 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
103 RESTArgs::get_string(s, "user-caps", caps, &caps);
104 RESTArgs::get_string(s, "tenant", tenant_name, &tenant_name);
105 RESTArgs::get_bool(s, "generate-key", true, &gen_key);
106 RESTArgs::get_bool(s, "suspended", false, &suspended);
107 RESTArgs::get_int32(s, "max-buckets", default_max_buckets, &max_buckets);
108 RESTArgs::get_bool(s, "system", false, &system);
109 RESTArgs::get_bool(s, "exclusive", false, &exclusive);
111 if (!s->user->system && system) {
112 ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl;
117 if (!tenant_name.empty()) {
118 uid.tenant = tenant_name;
121 // TODO: validate required args are passed in. (for eg. uid and display_name here)
122 op_state.set_user_id(uid);
123 op_state.set_display_name(display_name);
124 op_state.set_user_email(email);
125 op_state.set_caps(caps);
126 op_state.set_access_key(access_key);
127 op_state.set_secret_key(secret_key);
129 if (!key_type_str.empty()) {
130 int32_t key_type = KEY_TYPE_UNDEFINED;
131 if (key_type_str.compare("swift") == 0)
132 key_type = KEY_TYPE_SWIFT;
133 else if (key_type_str.compare("s3") == 0)
134 key_type = KEY_TYPE_S3;
136 op_state.set_key_type(key_type);
139 if (max_buckets != default_max_buckets)
140 op_state.set_max_buckets(max_buckets);
142 if (s->info.args.exists("suspended"))
143 op_state.set_suspension(suspended);
145 if (s->info.args.exists("system"))
146 op_state.set_system(system);
148 if (s->info.args.exists("exclusive"))
149 op_state.set_exclusive(exclusive);
152 op_state.set_generate_key();
154 RGWQuotaInfo bucket_quota;
155 RGWQuotaInfo user_quota;
157 if (s->cct->_conf->rgw_bucket_default_quota_max_objects >= 0) {
158 bucket_quota.max_objects = s->cct->_conf->rgw_bucket_default_quota_max_objects;
159 bucket_quota.enabled = true;
162 if (s->cct->_conf->rgw_bucket_default_quota_max_size >= 0) {
163 bucket_quota.max_size = s->cct->_conf->rgw_bucket_default_quota_max_size;
164 bucket_quota.enabled = true;
167 if (s->cct->_conf->rgw_user_default_quota_max_objects >= 0) {
168 user_quota.max_objects = s->cct->_conf->rgw_user_default_quota_max_objects;
169 user_quota.enabled = true;
172 if (s->cct->_conf->rgw_user_default_quota_max_size >= 0) {
173 user_quota.max_size = s->cct->_conf->rgw_user_default_quota_max_size;
174 user_quota.enabled = true;
177 if (bucket_quota.enabled) {
178 op_state.set_bucket_quota(bucket_quota);
181 if (user_quota.enabled) {
182 op_state.set_user_quota(user_quota);
185 http_ret = RGWUserAdminOp_User::create(store, op_state, flusher);
188 class RGWOp_User_Modify : public RGWRESTOp {
191 RGWOp_User_Modify() {}
193 int check_caps(RGWUserCaps& caps) override {
194 return caps.check_cap("users", RGW_CAP_WRITE);
197 void execute() override;
199 const string name() override { return "modify_user"; }
202 void RGWOp_User_Modify::execute()
205 std::string display_name;
207 std::string access_key;
208 std::string secret_key;
209 std::string key_type_str;
218 RGWUserAdminOpState op_state;
220 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
221 rgw_user uid(uid_str);
223 RESTArgs::get_string(s, "display-name", display_name, &display_name);
224 RESTArgs::get_string(s, "email", email, &email);
225 RESTArgs::get_string(s, "access-key", access_key, &access_key);
226 RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
227 RESTArgs::get_string(s, "user-caps", caps, &caps);
228 RESTArgs::get_bool(s, "generate-key", false, &gen_key);
229 RESTArgs::get_bool(s, "suspended", false, &suspended);
230 RESTArgs::get_int32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets);
231 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
233 RESTArgs::get_bool(s, "system", false, &system);
235 if (!s->user->system && system) {
236 ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl;
241 op_state.set_user_id(uid);
242 op_state.set_display_name(display_name);
243 op_state.set_user_email(email);
244 op_state.set_caps(caps);
245 op_state.set_access_key(access_key);
246 op_state.set_secret_key(secret_key);
248 if (max_buckets != RGW_DEFAULT_MAX_BUCKETS)
249 op_state.set_max_buckets(max_buckets);
252 op_state.set_generate_key();
254 if (!key_type_str.empty()) {
255 int32_t key_type = KEY_TYPE_UNDEFINED;
256 if (key_type_str.compare("swift") == 0)
257 key_type = KEY_TYPE_SWIFT;
258 else if (key_type_str.compare("s3") == 0)
259 key_type = KEY_TYPE_S3;
261 op_state.set_key_type(key_type);
264 if (s->info.args.exists("suspended"))
265 op_state.set_suspension(suspended);
267 if (s->info.args.exists("system"))
268 op_state.set_system(system);
270 http_ret = RGWUserAdminOp_User::modify(store, op_state, flusher);
273 class RGWOp_User_Remove : public RGWRESTOp {
276 RGWOp_User_Remove() {}
278 int check_caps(RGWUserCaps& caps) override {
279 return caps.check_cap("users", RGW_CAP_WRITE);
282 void execute() override;
284 const string name() override { return "remove_user"; }
287 void RGWOp_User_Remove::execute()
292 RGWUserAdminOpState op_state;
294 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
295 rgw_user uid(uid_str);
297 RESTArgs::get_bool(s, "purge-data", false, &purge_data);
299 // FIXME: no double checking
301 op_state.set_user_id(uid);
303 op_state.set_purge_data(purge_data);
305 http_ret = RGWUserAdminOp_User::remove(store, op_state, flusher);
308 class RGWOp_Subuser_Create : public RGWRESTOp {
311 RGWOp_Subuser_Create() {}
313 int check_caps(RGWUserCaps& caps) override {
314 return caps.check_cap("users", RGW_CAP_WRITE);
317 void execute() override;
319 const string name() override { return "create_subuser"; }
322 void RGWOp_Subuser_Create::execute()
326 std::string secret_key;
327 std::string access_key;
328 std::string perm_str;
329 std::string key_type_str;
331 bool gen_subuser = false; // FIXME placeholder
335 uint32_t perm_mask = 0;
336 int32_t key_type = KEY_TYPE_SWIFT;
338 RGWUserAdminOpState op_state;
340 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
341 rgw_user uid(uid_str);
343 RESTArgs::get_string(s, "subuser", subuser, &subuser);
344 RESTArgs::get_string(s, "access-key", access_key, &access_key);
345 RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
346 RESTArgs::get_string(s, "access", perm_str, &perm_str);
347 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
348 //RESTArgs::get_bool(s, "generate-subuser", false, &gen_subuser);
349 RESTArgs::get_bool(s, "generate-secret", false, &gen_secret);
350 RESTArgs::get_bool(s, "gen-access-key", false, &gen_access);
352 perm_mask = rgw_str_to_perm(perm_str.c_str());
353 op_state.set_perm(perm_mask);
355 op_state.set_user_id(uid);
356 op_state.set_subuser(subuser);
357 op_state.set_access_key(access_key);
358 op_state.set_secret_key(secret_key);
359 op_state.set_generate_subuser(gen_subuser);
362 op_state.set_gen_access();
365 op_state.set_gen_secret();
367 if (!key_type_str.empty()) {
368 if (key_type_str.compare("swift") == 0)
369 key_type = KEY_TYPE_SWIFT;
370 else if (key_type_str.compare("s3") == 0)
371 key_type = KEY_TYPE_S3;
373 op_state.set_key_type(key_type);
375 http_ret = RGWUserAdminOp_Subuser::create(store, op_state, flusher);
378 class RGWOp_Subuser_Modify : public RGWRESTOp {
381 RGWOp_Subuser_Modify() {}
383 int check_caps(RGWUserCaps& caps) override {
384 return caps.check_cap("users", RGW_CAP_WRITE);
387 void execute() override;
389 const string name() override { return "modify_subuser"; }
392 void RGWOp_Subuser_Modify::execute()
396 std::string secret_key;
397 std::string key_type_str;
398 std::string perm_str;
400 RGWUserAdminOpState op_state;
403 int32_t key_type = KEY_TYPE_SWIFT;
407 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
408 rgw_user uid(uid_str);
410 RESTArgs::get_string(s, "subuser", subuser, &subuser);
411 RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
412 RESTArgs::get_string(s, "access", perm_str, &perm_str);
413 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
414 RESTArgs::get_bool(s, "generate-secret", false, &gen_secret);
416 perm_mask = rgw_str_to_perm(perm_str.c_str());
417 op_state.set_perm(perm_mask);
419 op_state.set_user_id(uid);
420 op_state.set_subuser(subuser);
421 op_state.set_secret_key(secret_key);
422 op_state.set_gen_secret();
424 if (!key_type_str.empty()) {
425 if (key_type_str.compare("swift") == 0)
426 key_type = KEY_TYPE_SWIFT;
427 else if (key_type_str.compare("s3") == 0)
428 key_type = KEY_TYPE_S3;
430 op_state.set_key_type(key_type);
432 http_ret = RGWUserAdminOp_Subuser::modify(store, op_state, flusher);
435 class RGWOp_Subuser_Remove : public RGWRESTOp {
438 RGWOp_Subuser_Remove() {}
440 int check_caps(RGWUserCaps& caps) override {
441 return caps.check_cap("users", RGW_CAP_WRITE);
444 void execute() override;
446 const string name() override { return "remove_subuser"; }
449 void RGWOp_Subuser_Remove::execute()
455 RGWUserAdminOpState op_state;
457 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
458 rgw_user uid(uid_str);
460 RESTArgs::get_string(s, "subuser", subuser, &subuser);
461 RESTArgs::get_bool(s, "purge-keys", true, &purge_keys);
463 op_state.set_user_id(uid);
464 op_state.set_subuser(subuser);
467 op_state.set_purge_keys();
469 http_ret = RGWUserAdminOp_Subuser::remove(store, op_state, flusher);
472 class RGWOp_Key_Create : public RGWRESTOp {
475 RGWOp_Key_Create() {}
477 int check_caps(RGWUserCaps& caps) override {
478 return caps.check_cap("users", RGW_CAP_WRITE);
481 void execute() override;
483 const string name() override { return "create_access_key"; }
486 void RGWOp_Key_Create::execute()
490 std::string access_key;
491 std::string secret_key;
492 std::string key_type_str;
496 RGWUserAdminOpState op_state;
498 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
499 rgw_user uid(uid_str);
501 RESTArgs::get_string(s, "subuser", subuser, &subuser);
502 RESTArgs::get_string(s, "access-key", access_key, &access_key);
503 RESTArgs::get_string(s, "secret-key", secret_key, &secret_key);
504 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
505 RESTArgs::get_bool(s, "generate-key", true, &gen_key);
507 op_state.set_user_id(uid);
508 op_state.set_subuser(subuser);
509 op_state.set_access_key(access_key);
510 op_state.set_secret_key(secret_key);
513 op_state.set_generate_key();
515 if (!key_type_str.empty()) {
516 int32_t key_type = KEY_TYPE_UNDEFINED;
517 if (key_type_str.compare("swift") == 0)
518 key_type = KEY_TYPE_SWIFT;
519 else if (key_type_str.compare("s3") == 0)
520 key_type = KEY_TYPE_S3;
522 op_state.set_key_type(key_type);
525 http_ret = RGWUserAdminOp_Key::create(store, op_state, flusher);
528 class RGWOp_Key_Remove : public RGWRESTOp {
531 RGWOp_Key_Remove() {}
533 int check_caps(RGWUserCaps& caps) override {
534 return caps.check_cap("users", RGW_CAP_WRITE);
537 void execute() override;
539 const string name() override { return "remove_access_key"; }
542 void RGWOp_Key_Remove::execute()
546 std::string access_key;
547 std::string key_type_str;
549 RGWUserAdminOpState op_state;
551 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
552 rgw_user uid(uid_str);
554 RESTArgs::get_string(s, "subuser", subuser, &subuser);
555 RESTArgs::get_string(s, "access-key", access_key, &access_key);
556 RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str);
558 op_state.set_user_id(uid);
559 op_state.set_subuser(subuser);
560 op_state.set_access_key(access_key);
562 if (!key_type_str.empty()) {
563 int32_t key_type = KEY_TYPE_UNDEFINED;
564 if (key_type_str.compare("swift") == 0)
565 key_type = KEY_TYPE_SWIFT;
566 else if (key_type_str.compare("s3") == 0)
567 key_type = KEY_TYPE_S3;
569 op_state.set_key_type(key_type);
572 http_ret = RGWUserAdminOp_Key::remove(store, op_state, flusher);
575 class RGWOp_Caps_Add : public RGWRESTOp {
580 int check_caps(RGWUserCaps& caps) override {
581 return caps.check_cap("users", RGW_CAP_WRITE);
584 void execute() override;
586 const string name() override { return "add_user_caps"; }
589 void RGWOp_Caps_Add::execute()
594 RGWUserAdminOpState op_state;
596 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
597 rgw_user uid(uid_str);
599 RESTArgs::get_string(s, "user-caps", caps, &caps);
601 op_state.set_user_id(uid);
602 op_state.set_caps(caps);
604 http_ret = RGWUserAdminOp_Caps::add(store, op_state, flusher);
607 class RGWOp_Caps_Remove : public RGWRESTOp {
610 RGWOp_Caps_Remove() {}
612 int check_caps(RGWUserCaps& caps) override {
613 return caps.check_cap("users", RGW_CAP_WRITE);
616 void execute() override;
618 const string name() override { return "remove_user_caps"; }
621 void RGWOp_Caps_Remove::execute()
626 RGWUserAdminOpState op_state;
628 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
629 rgw_user uid(uid_str);
631 RESTArgs::get_string(s, "user-caps", caps, &caps);
633 op_state.set_user_id(uid);
634 op_state.set_caps(caps);
636 http_ret = RGWUserAdminOp_Caps::remove(store, op_state, flusher);
640 RGWQuotaInfo bucket_quota;
641 RGWQuotaInfo user_quota;
645 explicit UserQuotas(RGWUserInfo& info) : bucket_quota(info.bucket_quota),
646 user_quota(info.user_quota) {}
648 void dump(Formatter *f) const {
649 encode_json("bucket_quota", bucket_quota, f);
650 encode_json("user_quota", user_quota, f);
652 void decode_json(JSONObj *obj) {
653 JSONDecoder::decode_json("bucket_quota", bucket_quota, obj);
654 JSONDecoder::decode_json("user_quota", user_quota, obj);
658 class RGWOp_Quota_Info : public RGWRESTOp {
661 RGWOp_Quota_Info() {}
663 int check_caps(RGWUserCaps& caps) override {
664 return caps.check_cap("users", RGW_CAP_READ);
667 void execute() override;
669 const string name() override { return "get_quota_info"; }
673 void RGWOp_Quota_Info::execute()
675 RGWUserAdminOpState op_state;
678 std::string quota_type;
680 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
681 RESTArgs::get_string(s, "quota-type", quota_type, "a_type);
683 if (uid_str.empty()) {
688 rgw_user uid(uid_str);
690 bool show_all = quota_type.empty();
691 bool show_bucket = show_all || (quota_type == "bucket");
692 bool show_user = show_all || (quota_type == "user");
694 if (!(show_all || show_bucket || show_user)) {
699 op_state.set_user_id(uid);
702 http_ret = user.init(store, op_state);
706 if (!op_state.has_existing_user()) {
707 http_ret = -ERR_NO_SUCH_USER;
713 http_ret = user.info(info, &err_msg);
719 UserQuotas quotas(info);
720 encode_json("quota", quotas, s->formatter);
721 } else if (show_user) {
722 encode_json("user_quota", info.user_quota, s->formatter);
724 encode_json("bucket_quota", info.bucket_quota, s->formatter);
730 class RGWOp_Quota_Set : public RGWRESTOp {
735 int check_caps(RGWUserCaps& caps) override {
736 return caps.check_cap("users", RGW_CAP_WRITE);
739 void execute() override;
741 const string name() override { return "set_quota_info"; }
747 * two different ways to set the quota info: as json struct in the message body or via http params.
751 * PUT /admin/user?uid=<uid>["a-type=<type>]
753 * whereas quota-type is optional and is either user, or bucket
755 * if quota-type is not specified then we expect to get a structure that contains both quotas,
756 * otherwise we'll only get the relevant configuration.
758 * E.g., if quota type not specified:
761 * "max_size_kb" : 4096,
762 * "max_objects" : -1,
766 * "max_size_kb" : 1024,
767 * "max_objects" : -1,
773 * or if quota type is specified:
775 * "max_size_kb" : 4096,
776 * "max_objects" : -1,
780 * Another option is not to pass any body and set the following http params:
784 * max-objects=<max objects>
785 * enabled[={true,false}]
787 * all params are optionals and default to the current settings. With this type of configuration the
788 * quota-type param is mandatory.
792 void RGWOp_Quota_Set::execute()
794 RGWUserAdminOpState op_state;
797 std::string quota_type;
799 RESTArgs::get_string(s, "uid", uid_str, &uid_str);
800 RESTArgs::get_string(s, "quota-type", quota_type, "a_type);
802 if (uid_str.empty()) {
807 rgw_user uid(uid_str);
809 bool set_all = quota_type.empty();
810 bool set_bucket = set_all || (quota_type == "bucket");
811 bool set_user = set_all || (quota_type == "user");
813 if (!(set_all || set_bucket || set_user)) {
814 ldout(store->ctx(), 20) << "invalid quota type" << dendl;
819 bool use_http_params;
821 if (s->content_length > 0) {
822 use_http_params = false;
824 const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING");
825 use_http_params = (!encoding || strcmp(encoding, "chunked") != 0);
828 if (use_http_params && set_all) {
829 ldout(store->ctx(), 20) << "quota type was not specified, can't set all quotas via http headers" << dendl;
834 op_state.set_user_id(uid);
837 http_ret = user.init(store, op_state);
839 ldout(store->ctx(), 20) << "failed initializing user info: " << http_ret << dendl;
843 if (!op_state.has_existing_user()) {
844 http_ret = -ERR_NO_SUCH_USER;
848 #define QUOTA_INPUT_MAX_LEN 1024
852 if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, quotas, QUOTA_INPUT_MAX_LEN, NULL)) < 0) {
853 ldout(store->ctx(), 20) << "failed to retrieve input" << dendl;
857 op_state.set_user_quota(quotas.user_quota);
858 op_state.set_bucket_quota(quotas.bucket_quota);
862 if (!use_http_params) {
864 http_ret = rgw_rest_get_json_input(store->ctx(), s, quota, QUOTA_INPUT_MAX_LEN, &empty);
866 ldout(store->ctx(), 20) << "failed to retrieve input" << dendl;
870 /* was probably chunked input, but no content provided, configure via http params */
871 use_http_params = true;
875 if (use_http_params) {
878 http_ret = user.info(info, &err_msg);
880 ldout(store->ctx(), 20) << "failed to get user info: " << http_ret << dendl;
883 RGWQuotaInfo *old_quota;
885 old_quota = &info.user_quota;
887 old_quota = &info.bucket_quota;
890 int64_t old_max_size_kb = rgw_rounded_kb(old_quota->max_size);
892 RESTArgs::get_int64(s, "max-objects", old_quota->max_objects, "a.max_objects);
893 RESTArgs::get_int64(s, "max-size-kb", old_max_size_kb, &max_size_kb);
894 quota.max_size = max_size_kb * 1024;
895 RESTArgs::get_bool(s, "enabled", old_quota->enabled, "a.enabled);
899 op_state.set_user_quota(quota);
901 op_state.set_bucket_quota(quota);
906 http_ret = user.modify(op_state, &err);
908 ldout(store->ctx(), 20) << "failed updating user info: " << http_ret << ": " << err << dendl;
913 RGWOp *RGWHandler_User::op_get()
915 if (s->info.args.sub_resource_exists("quota"))
916 return new RGWOp_Quota_Info;
918 return new RGWOp_User_Info;
921 RGWOp *RGWHandler_User::op_put()
923 if (s->info.args.sub_resource_exists("subuser"))
924 return new RGWOp_Subuser_Create;
926 if (s->info.args.sub_resource_exists("key"))
927 return new RGWOp_Key_Create;
929 if (s->info.args.sub_resource_exists("caps"))
930 return new RGWOp_Caps_Add;
932 if (s->info.args.sub_resource_exists("quota"))
933 return new RGWOp_Quota_Set;
935 return new RGWOp_User_Create;
938 RGWOp *RGWHandler_User::op_post()
940 if (s->info.args.sub_resource_exists("subuser"))
941 return new RGWOp_Subuser_Modify;
943 return new RGWOp_User_Modify;
946 RGWOp *RGWHandler_User::op_delete()
948 if (s->info.args.sub_resource_exists("subuser"))
949 return new RGWOp_Subuser_Remove;
951 if (s->info.args.sub_resource_exists("key"))
952 return new RGWOp_Key_Remove;
954 if (s->info.args.sub_resource_exists("caps"))
955 return new RGWOp_Caps_Remove;
957 return new RGWOp_User_Remove;