]>
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 "common/ceph_json.h" | |
5 | ||
6 | #include "rgw_op.h" | |
7 | #include "rgw_user.h" | |
8 | #include "rgw_rest_user.h" | |
9 | ||
10 | #include "include/str_list.h" | |
11fdf7f2 | 11 | #include "include/ceph_assert.h" |
7c673cae | 12 | |
9f95a23c TL |
13 | #include "services/svc_zone.h" |
14 | #include "services/svc_sys_obj.h" | |
15 | #include "rgw_zone.h" | |
16 | ||
7c673cae FG |
17 | #define dout_subsys ceph_subsys_rgw |
18 | ||
11fdf7f2 TL |
19 | class RGWOp_User_List : public RGWRESTOp { |
20 | ||
21 | public: | |
22 | RGWOp_User_List() {} | |
23 | ||
9f95a23c | 24 | int check_caps(const RGWUserCaps& caps) override { |
11fdf7f2 TL |
25 | return caps.check_cap("users", RGW_CAP_READ); |
26 | } | |
27 | ||
28 | void execute() override; | |
29 | ||
30 | const char* name() const override { return "list_user"; } | |
31 | }; | |
32 | ||
33 | void RGWOp_User_List::execute() | |
34 | { | |
35 | RGWUserAdminOpState op_state; | |
36 | ||
37 | uint32_t max_entries; | |
38 | std::string marker; | |
39 | RESTArgs::get_uint32(s, "max-entries", 1000, &max_entries); | |
40 | RESTArgs::get_string(s, "marker", marker, &marker); | |
41 | ||
42 | op_state.max_entries = max_entries; | |
43 | op_state.marker = marker; | |
44 | http_ret = RGWUserAdminOp_User::list(store, op_state, flusher); | |
45 | } | |
46 | ||
7c673cae FG |
47 | class RGWOp_User_Info : public RGWRESTOp { |
48 | ||
49 | public: | |
50 | RGWOp_User_Info() {} | |
51 | ||
9f95a23c | 52 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
53 | return caps.check_cap("users", RGW_CAP_READ); |
54 | } | |
55 | ||
56 | void execute() override; | |
57 | ||
11fdf7f2 | 58 | const char* name() const override { return "get_user_info"; } |
7c673cae FG |
59 | }; |
60 | ||
61 | void RGWOp_User_Info::execute() | |
62 | { | |
63 | RGWUserAdminOpState op_state; | |
64 | ||
11fdf7f2 | 65 | std::string uid_str, access_key_str; |
7c673cae | 66 | bool fetch_stats; |
3efd9988 | 67 | bool sync_stats; |
7c673cae FG |
68 | |
69 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
11fdf7f2 | 70 | RESTArgs::get_string(s, "access-key", access_key_str, &access_key_str); |
7c673cae FG |
71 | |
72 | // if uid was not supplied in rest argument, error out now, otherwise we'll | |
73 | // end up initializing anonymous user, for which keys.init will eventually | |
74 | // return -EACESS | |
11fdf7f2 | 75 | if (uid_str.empty() && access_key_str.empty()){ |
7c673cae FG |
76 | http_ret=-EINVAL; |
77 | return; | |
78 | } | |
79 | ||
80 | rgw_user uid(uid_str); | |
81 | ||
82 | RESTArgs::get_bool(s, "stats", false, &fetch_stats); | |
83 | ||
3efd9988 FG |
84 | RESTArgs::get_bool(s, "sync", false, &sync_stats); |
85 | ||
7c673cae | 86 | op_state.set_user_id(uid); |
11fdf7f2 | 87 | op_state.set_access_key(access_key_str); |
7c673cae | 88 | op_state.set_fetch_stats(fetch_stats); |
3efd9988 | 89 | op_state.set_sync_stats(sync_stats); |
7c673cae FG |
90 | |
91 | http_ret = RGWUserAdminOp_User::info(store, op_state, flusher); | |
92 | } | |
93 | ||
94 | class RGWOp_User_Create : public RGWRESTOp { | |
95 | ||
96 | public: | |
97 | RGWOp_User_Create() {} | |
98 | ||
9f95a23c | 99 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
100 | return caps.check_cap("users", RGW_CAP_WRITE); |
101 | } | |
102 | ||
103 | void execute() override; | |
104 | ||
11fdf7f2 | 105 | const char* name() const override { return "create_user"; } |
7c673cae FG |
106 | }; |
107 | ||
108 | void RGWOp_User_Create::execute() | |
109 | { | |
110 | std::string uid_str; | |
111 | std::string display_name; | |
112 | std::string email; | |
113 | std::string access_key; | |
114 | std::string secret_key; | |
115 | std::string key_type_str; | |
116 | std::string caps; | |
d2e6a577 | 117 | std::string tenant_name; |
11fdf7f2 | 118 | std::string op_mask_str; |
9f95a23c TL |
119 | std::string default_placement_str; |
120 | std::string placement_tags_str; | |
7c673cae FG |
121 | |
122 | bool gen_key; | |
123 | bool suspended; | |
124 | bool system; | |
125 | bool exclusive; | |
126 | ||
127 | int32_t max_buckets; | |
128 | int32_t default_max_buckets = s->cct->_conf->rgw_user_max_buckets; | |
129 | ||
130 | RGWUserAdminOpState op_state; | |
131 | ||
132 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
133 | rgw_user uid(uid_str); | |
134 | ||
135 | RESTArgs::get_string(s, "display-name", display_name, &display_name); | |
136 | RESTArgs::get_string(s, "email", email, &email); | |
137 | RESTArgs::get_string(s, "access-key", access_key, &access_key); | |
138 | RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); | |
139 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); | |
140 | RESTArgs::get_string(s, "user-caps", caps, &caps); | |
d2e6a577 | 141 | RESTArgs::get_string(s, "tenant", tenant_name, &tenant_name); |
7c673cae FG |
142 | RESTArgs::get_bool(s, "generate-key", true, &gen_key); |
143 | RESTArgs::get_bool(s, "suspended", false, &suspended); | |
144 | RESTArgs::get_int32(s, "max-buckets", default_max_buckets, &max_buckets); | |
145 | RESTArgs::get_bool(s, "system", false, &system); | |
146 | RESTArgs::get_bool(s, "exclusive", false, &exclusive); | |
11fdf7f2 | 147 | RESTArgs::get_string(s, "op-mask", op_mask_str, &op_mask_str); |
9f95a23c TL |
148 | RESTArgs::get_string(s, "default-placement", default_placement_str, &default_placement_str); |
149 | RESTArgs::get_string(s, "placement-tags", placement_tags_str, &placement_tags_str); | |
7c673cae | 150 | |
9f95a23c | 151 | if (!s->user->get_info().system && system) { |
7c673cae FG |
152 | ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl; |
153 | http_ret = -EINVAL; | |
154 | return; | |
155 | } | |
156 | ||
d2e6a577 FG |
157 | if (!tenant_name.empty()) { |
158 | uid.tenant = tenant_name; | |
159 | } | |
160 | ||
7c673cae FG |
161 | // TODO: validate required args are passed in. (for eg. uid and display_name here) |
162 | op_state.set_user_id(uid); | |
163 | op_state.set_display_name(display_name); | |
164 | op_state.set_user_email(email); | |
165 | op_state.set_caps(caps); | |
166 | op_state.set_access_key(access_key); | |
167 | op_state.set_secret_key(secret_key); | |
168 | ||
11fdf7f2 TL |
169 | if (!op_mask_str.empty()) { |
170 | uint32_t op_mask; | |
171 | int ret = rgw_parse_op_type_list(op_mask_str, &op_mask); | |
172 | if (ret < 0) { | |
173 | ldout(s->cct, 0) << "failed to parse op_mask: " << ret << dendl; | |
174 | http_ret = -EINVAL; | |
175 | return; | |
176 | } | |
177 | op_state.set_op_mask(op_mask); | |
178 | } | |
179 | ||
7c673cae FG |
180 | if (!key_type_str.empty()) { |
181 | int32_t key_type = KEY_TYPE_UNDEFINED; | |
182 | if (key_type_str.compare("swift") == 0) | |
183 | key_type = KEY_TYPE_SWIFT; | |
184 | else if (key_type_str.compare("s3") == 0) | |
185 | key_type = KEY_TYPE_S3; | |
186 | ||
187 | op_state.set_key_type(key_type); | |
188 | } | |
189 | ||
9f95a23c TL |
190 | if (max_buckets != default_max_buckets) { |
191 | if (max_buckets < 0) { | |
192 | max_buckets = -1; | |
193 | } | |
7c673cae | 194 | op_state.set_max_buckets(max_buckets); |
9f95a23c | 195 | } |
7c673cae FG |
196 | if (s->info.args.exists("suspended")) |
197 | op_state.set_suspension(suspended); | |
198 | ||
199 | if (s->info.args.exists("system")) | |
200 | op_state.set_system(system); | |
201 | ||
202 | if (s->info.args.exists("exclusive")) | |
203 | op_state.set_exclusive(exclusive); | |
204 | ||
205 | if (gen_key) | |
206 | op_state.set_generate_key(); | |
207 | ||
9f95a23c TL |
208 | if (!default_placement_str.empty()) { |
209 | rgw_placement_rule target_rule; | |
210 | target_rule.from_str(default_placement_str); | |
211 | if (!store->svc()->zone->get_zone_params().valid_placement(target_rule)) { | |
212 | ldout(s->cct, 0) << "NOTICE: invalid dest placement: " << target_rule.to_str() << dendl; | |
213 | http_ret = -EINVAL; | |
214 | return; | |
215 | } | |
216 | op_state.set_default_placement(target_rule); | |
217 | } | |
218 | ||
219 | if (!placement_tags_str.empty()) { | |
220 | list<string> placement_tags_list; | |
221 | get_str_list(placement_tags_str, ",", placement_tags_list); | |
222 | op_state.set_placement_tags(placement_tags_list); | |
223 | } | |
224 | ||
225 | if (!store->svc()->zone->is_meta_master()) { | |
226 | bufferlist data; | |
227 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
228 | if (op_ret < 0) { | |
229 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
230 | return; | |
231 | } | |
232 | } | |
7c673cae FG |
233 | http_ret = RGWUserAdminOp_User::create(store, op_state, flusher); |
234 | } | |
235 | ||
236 | class RGWOp_User_Modify : public RGWRESTOp { | |
237 | ||
238 | public: | |
239 | RGWOp_User_Modify() {} | |
240 | ||
9f95a23c | 241 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
242 | return caps.check_cap("users", RGW_CAP_WRITE); |
243 | } | |
244 | ||
245 | void execute() override; | |
246 | ||
11fdf7f2 | 247 | const char* name() const override { return "modify_user"; } |
7c673cae FG |
248 | }; |
249 | ||
250 | void RGWOp_User_Modify::execute() | |
251 | { | |
252 | std::string uid_str; | |
253 | std::string display_name; | |
254 | std::string email; | |
255 | std::string access_key; | |
256 | std::string secret_key; | |
257 | std::string key_type_str; | |
258 | std::string caps; | |
11fdf7f2 | 259 | std::string op_mask_str; |
9f95a23c TL |
260 | std::string default_placement_str; |
261 | std::string placement_tags_str; | |
7c673cae FG |
262 | |
263 | bool gen_key; | |
264 | bool suspended; | |
265 | bool system; | |
28e407b8 | 266 | bool email_set; |
94b18763 | 267 | bool quota_set; |
7c673cae FG |
268 | int32_t max_buckets; |
269 | ||
270 | RGWUserAdminOpState op_state; | |
271 | ||
272 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
273 | rgw_user uid(uid_str); | |
274 | ||
275 | RESTArgs::get_string(s, "display-name", display_name, &display_name); | |
28e407b8 | 276 | RESTArgs::get_string(s, "email", email, &email, &email_set); |
7c673cae FG |
277 | RESTArgs::get_string(s, "access-key", access_key, &access_key); |
278 | RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); | |
279 | RESTArgs::get_string(s, "user-caps", caps, &caps); | |
280 | RESTArgs::get_bool(s, "generate-key", false, &gen_key); | |
281 | RESTArgs::get_bool(s, "suspended", false, &suspended); | |
94b18763 | 282 | RESTArgs::get_int32(s, "max-buckets", RGW_DEFAULT_MAX_BUCKETS, &max_buckets, "a_set); |
7c673cae FG |
283 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); |
284 | ||
285 | RESTArgs::get_bool(s, "system", false, &system); | |
11fdf7f2 | 286 | RESTArgs::get_string(s, "op-mask", op_mask_str, &op_mask_str); |
9f95a23c TL |
287 | RESTArgs::get_string(s, "default-placement", default_placement_str, &default_placement_str); |
288 | RESTArgs::get_string(s, "placement-tags", placement_tags_str, &placement_tags_str); | |
7c673cae | 289 | |
9f95a23c | 290 | if (!s->user->get_info().system && system) { |
7c673cae FG |
291 | ldout(s->cct, 0) << "cannot set system flag by non-system user" << dendl; |
292 | http_ret = -EINVAL; | |
293 | return; | |
294 | } | |
295 | ||
296 | op_state.set_user_id(uid); | |
297 | op_state.set_display_name(display_name); | |
28e407b8 AA |
298 | |
299 | if (email_set) | |
300 | op_state.set_user_email(email); | |
301 | ||
7c673cae FG |
302 | op_state.set_caps(caps); |
303 | op_state.set_access_key(access_key); | |
304 | op_state.set_secret_key(secret_key); | |
305 | ||
9f95a23c TL |
306 | if (quota_set) { |
307 | if (max_buckets < 0 ) { | |
308 | max_buckets = -1; | |
309 | } | |
7c673cae | 310 | op_state.set_max_buckets(max_buckets); |
9f95a23c | 311 | } |
7c673cae FG |
312 | if (gen_key) |
313 | op_state.set_generate_key(); | |
314 | ||
315 | if (!key_type_str.empty()) { | |
316 | int32_t key_type = KEY_TYPE_UNDEFINED; | |
317 | if (key_type_str.compare("swift") == 0) | |
318 | key_type = KEY_TYPE_SWIFT; | |
319 | else if (key_type_str.compare("s3") == 0) | |
320 | key_type = KEY_TYPE_S3; | |
321 | ||
322 | op_state.set_key_type(key_type); | |
323 | } | |
324 | ||
9f95a23c TL |
325 | if (!op_mask_str.empty()) { |
326 | uint32_t op_mask; | |
327 | if (rgw_parse_op_type_list(op_mask_str, &op_mask) < 0) { | |
328 | ldout(s->cct, 0) << "failed to parse op_mask" << dendl; | |
329 | http_ret = -EINVAL; | |
330 | return; | |
331 | } | |
332 | op_state.set_op_mask(op_mask); | |
333 | } | |
334 | ||
7c673cae FG |
335 | if (s->info.args.exists("suspended")) |
336 | op_state.set_suspension(suspended); | |
337 | ||
338 | if (s->info.args.exists("system")) | |
339 | op_state.set_system(system); | |
340 | ||
11fdf7f2 TL |
341 | if (!op_mask_str.empty()) { |
342 | uint32_t op_mask; | |
343 | int ret = rgw_parse_op_type_list(op_mask_str, &op_mask); | |
344 | if (ret < 0) { | |
345 | ldout(s->cct, 0) << "failed to parse op_mask: " << ret << dendl; | |
346 | http_ret = -EINVAL; | |
347 | return; | |
348 | } | |
349 | op_state.set_op_mask(op_mask); | |
350 | } | |
351 | ||
9f95a23c TL |
352 | if (!default_placement_str.empty()) { |
353 | rgw_placement_rule target_rule; | |
354 | target_rule.from_str(default_placement_str); | |
355 | if (!store->svc()->zone->get_zone_params().valid_placement(target_rule)) { | |
356 | ldout(s->cct, 0) << "NOTICE: invalid dest placement: " << target_rule.to_str() << dendl; | |
357 | http_ret = -EINVAL; | |
358 | return; | |
359 | } | |
360 | op_state.set_default_placement(target_rule); | |
361 | } | |
362 | ||
363 | if (!placement_tags_str.empty()) { | |
364 | list<string> placement_tags_list; | |
365 | get_str_list(placement_tags_str, ",", placement_tags_list); | |
366 | op_state.set_placement_tags(placement_tags_list); | |
367 | } | |
368 | ||
369 | if (!store->svc()->zone->is_meta_master()) { | |
370 | bufferlist data; | |
371 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
372 | if (op_ret < 0) { | |
373 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
374 | return; | |
375 | } | |
376 | } | |
7c673cae FG |
377 | http_ret = RGWUserAdminOp_User::modify(store, op_state, flusher); |
378 | } | |
379 | ||
380 | class RGWOp_User_Remove : public RGWRESTOp { | |
381 | ||
382 | public: | |
383 | RGWOp_User_Remove() {} | |
384 | ||
9f95a23c | 385 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
386 | return caps.check_cap("users", RGW_CAP_WRITE); |
387 | } | |
388 | ||
389 | void execute() override; | |
390 | ||
11fdf7f2 | 391 | const char* name() const override { return "remove_user"; } |
7c673cae FG |
392 | }; |
393 | ||
394 | void RGWOp_User_Remove::execute() | |
395 | { | |
396 | std::string uid_str; | |
397 | bool purge_data; | |
398 | ||
399 | RGWUserAdminOpState op_state; | |
400 | ||
401 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
402 | rgw_user uid(uid_str); | |
403 | ||
404 | RESTArgs::get_bool(s, "purge-data", false, &purge_data); | |
405 | ||
406 | // FIXME: no double checking | |
407 | if (!uid.empty()) | |
408 | op_state.set_user_id(uid); | |
409 | ||
410 | op_state.set_purge_data(purge_data); | |
411 | ||
9f95a23c TL |
412 | if (!store->svc()->zone->is_meta_master()) { |
413 | bufferlist data; | |
414 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
415 | if (op_ret < 0) { | |
416 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
417 | return; | |
418 | } | |
419 | } | |
420 | http_ret = RGWUserAdminOp_User::remove(store, op_state, flusher, s->yield); | |
7c673cae FG |
421 | } |
422 | ||
423 | class RGWOp_Subuser_Create : public RGWRESTOp { | |
424 | ||
425 | public: | |
426 | RGWOp_Subuser_Create() {} | |
427 | ||
9f95a23c | 428 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
429 | return caps.check_cap("users", RGW_CAP_WRITE); |
430 | } | |
431 | ||
432 | void execute() override; | |
433 | ||
11fdf7f2 | 434 | const char* name() const override { return "create_subuser"; } |
7c673cae FG |
435 | }; |
436 | ||
437 | void RGWOp_Subuser_Create::execute() | |
438 | { | |
439 | std::string uid_str; | |
440 | std::string subuser; | |
441 | std::string secret_key; | |
442 | std::string access_key; | |
443 | std::string perm_str; | |
444 | std::string key_type_str; | |
445 | ||
446 | bool gen_subuser = false; // FIXME placeholder | |
447 | bool gen_secret; | |
448 | bool gen_access; | |
449 | ||
450 | uint32_t perm_mask = 0; | |
451 | int32_t key_type = KEY_TYPE_SWIFT; | |
452 | ||
453 | RGWUserAdminOpState op_state; | |
454 | ||
455 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
456 | rgw_user uid(uid_str); | |
457 | ||
458 | RESTArgs::get_string(s, "subuser", subuser, &subuser); | |
459 | RESTArgs::get_string(s, "access-key", access_key, &access_key); | |
460 | RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); | |
461 | RESTArgs::get_string(s, "access", perm_str, &perm_str); | |
462 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); | |
463 | //RESTArgs::get_bool(s, "generate-subuser", false, &gen_subuser); | |
464 | RESTArgs::get_bool(s, "generate-secret", false, &gen_secret); | |
465 | RESTArgs::get_bool(s, "gen-access-key", false, &gen_access); | |
466 | ||
467 | perm_mask = rgw_str_to_perm(perm_str.c_str()); | |
468 | op_state.set_perm(perm_mask); | |
469 | ||
470 | op_state.set_user_id(uid); | |
471 | op_state.set_subuser(subuser); | |
472 | op_state.set_access_key(access_key); | |
473 | op_state.set_secret_key(secret_key); | |
474 | op_state.set_generate_subuser(gen_subuser); | |
475 | ||
476 | if (gen_access) | |
477 | op_state.set_gen_access(); | |
478 | ||
479 | if (gen_secret) | |
480 | op_state.set_gen_secret(); | |
481 | ||
482 | if (!key_type_str.empty()) { | |
483 | if (key_type_str.compare("swift") == 0) | |
484 | key_type = KEY_TYPE_SWIFT; | |
485 | else if (key_type_str.compare("s3") == 0) | |
486 | key_type = KEY_TYPE_S3; | |
487 | } | |
488 | op_state.set_key_type(key_type); | |
489 | ||
9f95a23c TL |
490 | if (!store->svc()->zone->is_meta_master()) { |
491 | bufferlist data; | |
492 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
493 | if (op_ret < 0) { | |
494 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
495 | return; | |
496 | } | |
497 | } | |
7c673cae FG |
498 | http_ret = RGWUserAdminOp_Subuser::create(store, op_state, flusher); |
499 | } | |
500 | ||
501 | class RGWOp_Subuser_Modify : public RGWRESTOp { | |
502 | ||
503 | public: | |
504 | RGWOp_Subuser_Modify() {} | |
505 | ||
9f95a23c | 506 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
507 | return caps.check_cap("users", RGW_CAP_WRITE); |
508 | } | |
509 | ||
510 | void execute() override; | |
511 | ||
11fdf7f2 | 512 | const char* name() const override { return "modify_subuser"; } |
7c673cae FG |
513 | }; |
514 | ||
515 | void RGWOp_Subuser_Modify::execute() | |
516 | { | |
517 | std::string uid_str; | |
518 | std::string subuser; | |
519 | std::string secret_key; | |
520 | std::string key_type_str; | |
521 | std::string perm_str; | |
522 | ||
523 | RGWUserAdminOpState op_state; | |
524 | ||
525 | uint32_t perm_mask; | |
526 | int32_t key_type = KEY_TYPE_SWIFT; | |
527 | ||
528 | bool gen_secret; | |
529 | ||
530 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
531 | rgw_user uid(uid_str); | |
532 | ||
533 | RESTArgs::get_string(s, "subuser", subuser, &subuser); | |
534 | RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); | |
535 | RESTArgs::get_string(s, "access", perm_str, &perm_str); | |
536 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); | |
537 | RESTArgs::get_bool(s, "generate-secret", false, &gen_secret); | |
538 | ||
539 | perm_mask = rgw_str_to_perm(perm_str.c_str()); | |
540 | op_state.set_perm(perm_mask); | |
541 | ||
542 | op_state.set_user_id(uid); | |
543 | op_state.set_subuser(subuser); | |
b32b8144 FG |
544 | |
545 | if (!secret_key.empty()) | |
546 | op_state.set_secret_key(secret_key); | |
547 | ||
548 | if (gen_secret) | |
549 | op_state.set_gen_secret(); | |
7c673cae FG |
550 | |
551 | if (!key_type_str.empty()) { | |
552 | if (key_type_str.compare("swift") == 0) | |
553 | key_type = KEY_TYPE_SWIFT; | |
554 | else if (key_type_str.compare("s3") == 0) | |
555 | key_type = KEY_TYPE_S3; | |
556 | } | |
557 | op_state.set_key_type(key_type); | |
558 | ||
9f95a23c TL |
559 | if (!store->svc()->zone->is_meta_master()) { |
560 | bufferlist data; | |
561 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
562 | if (op_ret < 0) { | |
563 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
564 | return; | |
565 | } | |
566 | } | |
7c673cae FG |
567 | http_ret = RGWUserAdminOp_Subuser::modify(store, op_state, flusher); |
568 | } | |
569 | ||
570 | class RGWOp_Subuser_Remove : public RGWRESTOp { | |
571 | ||
572 | public: | |
573 | RGWOp_Subuser_Remove() {} | |
574 | ||
9f95a23c | 575 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
576 | return caps.check_cap("users", RGW_CAP_WRITE); |
577 | } | |
578 | ||
579 | void execute() override; | |
580 | ||
11fdf7f2 | 581 | const char* name() const override { return "remove_subuser"; } |
7c673cae FG |
582 | }; |
583 | ||
584 | void RGWOp_Subuser_Remove::execute() | |
585 | { | |
586 | std::string uid_str; | |
587 | std::string subuser; | |
588 | bool purge_keys; | |
589 | ||
590 | RGWUserAdminOpState op_state; | |
591 | ||
592 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
593 | rgw_user uid(uid_str); | |
594 | ||
595 | RESTArgs::get_string(s, "subuser", subuser, &subuser); | |
596 | RESTArgs::get_bool(s, "purge-keys", true, &purge_keys); | |
597 | ||
598 | op_state.set_user_id(uid); | |
599 | op_state.set_subuser(subuser); | |
600 | ||
601 | if (purge_keys) | |
602 | op_state.set_purge_keys(); | |
603 | ||
9f95a23c TL |
604 | if (!store->svc()->zone->is_meta_master()) { |
605 | bufferlist data; | |
606 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
607 | if (op_ret < 0) { | |
608 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
609 | return; | |
610 | } | |
611 | } | |
7c673cae FG |
612 | http_ret = RGWUserAdminOp_Subuser::remove(store, op_state, flusher); |
613 | } | |
614 | ||
615 | class RGWOp_Key_Create : public RGWRESTOp { | |
616 | ||
617 | public: | |
618 | RGWOp_Key_Create() {} | |
619 | ||
9f95a23c | 620 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
621 | return caps.check_cap("users", RGW_CAP_WRITE); |
622 | } | |
623 | ||
624 | void execute() override; | |
625 | ||
11fdf7f2 | 626 | const char* name() const override { return "create_access_key"; } |
7c673cae FG |
627 | }; |
628 | ||
629 | void RGWOp_Key_Create::execute() | |
630 | { | |
631 | std::string uid_str; | |
632 | std::string subuser; | |
633 | std::string access_key; | |
634 | std::string secret_key; | |
635 | std::string key_type_str; | |
636 | ||
637 | bool gen_key; | |
638 | ||
639 | RGWUserAdminOpState op_state; | |
640 | ||
641 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
642 | rgw_user uid(uid_str); | |
643 | ||
644 | RESTArgs::get_string(s, "subuser", subuser, &subuser); | |
645 | RESTArgs::get_string(s, "access-key", access_key, &access_key); | |
646 | RESTArgs::get_string(s, "secret-key", secret_key, &secret_key); | |
647 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); | |
648 | RESTArgs::get_bool(s, "generate-key", true, &gen_key); | |
649 | ||
650 | op_state.set_user_id(uid); | |
651 | op_state.set_subuser(subuser); | |
652 | op_state.set_access_key(access_key); | |
653 | op_state.set_secret_key(secret_key); | |
654 | ||
655 | if (gen_key) | |
656 | op_state.set_generate_key(); | |
657 | ||
658 | if (!key_type_str.empty()) { | |
659 | int32_t key_type = KEY_TYPE_UNDEFINED; | |
660 | if (key_type_str.compare("swift") == 0) | |
661 | key_type = KEY_TYPE_SWIFT; | |
662 | else if (key_type_str.compare("s3") == 0) | |
663 | key_type = KEY_TYPE_S3; | |
664 | ||
665 | op_state.set_key_type(key_type); | |
666 | } | |
667 | ||
668 | http_ret = RGWUserAdminOp_Key::create(store, op_state, flusher); | |
669 | } | |
670 | ||
671 | class RGWOp_Key_Remove : public RGWRESTOp { | |
672 | ||
673 | public: | |
674 | RGWOp_Key_Remove() {} | |
675 | ||
9f95a23c | 676 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
677 | return caps.check_cap("users", RGW_CAP_WRITE); |
678 | } | |
679 | ||
680 | void execute() override; | |
681 | ||
11fdf7f2 | 682 | const char* name() const override { return "remove_access_key"; } |
7c673cae FG |
683 | }; |
684 | ||
685 | void RGWOp_Key_Remove::execute() | |
686 | { | |
687 | std::string uid_str; | |
688 | std::string subuser; | |
689 | std::string access_key; | |
690 | std::string key_type_str; | |
691 | ||
692 | RGWUserAdminOpState op_state; | |
693 | ||
694 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
695 | rgw_user uid(uid_str); | |
696 | ||
697 | RESTArgs::get_string(s, "subuser", subuser, &subuser); | |
698 | RESTArgs::get_string(s, "access-key", access_key, &access_key); | |
699 | RESTArgs::get_string(s, "key-type", key_type_str, &key_type_str); | |
700 | ||
701 | op_state.set_user_id(uid); | |
702 | op_state.set_subuser(subuser); | |
703 | op_state.set_access_key(access_key); | |
704 | ||
705 | if (!key_type_str.empty()) { | |
706 | int32_t key_type = KEY_TYPE_UNDEFINED; | |
707 | if (key_type_str.compare("swift") == 0) | |
708 | key_type = KEY_TYPE_SWIFT; | |
709 | else if (key_type_str.compare("s3") == 0) | |
710 | key_type = KEY_TYPE_S3; | |
711 | ||
712 | op_state.set_key_type(key_type); | |
713 | } | |
714 | ||
715 | http_ret = RGWUserAdminOp_Key::remove(store, op_state, flusher); | |
716 | } | |
717 | ||
718 | class RGWOp_Caps_Add : public RGWRESTOp { | |
719 | ||
720 | public: | |
721 | RGWOp_Caps_Add() {} | |
722 | ||
9f95a23c | 723 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
724 | return caps.check_cap("users", RGW_CAP_WRITE); |
725 | } | |
726 | ||
727 | void execute() override; | |
728 | ||
11fdf7f2 | 729 | const char* name() const override { return "add_user_caps"; } |
7c673cae FG |
730 | }; |
731 | ||
732 | void RGWOp_Caps_Add::execute() | |
733 | { | |
734 | std::string uid_str; | |
735 | std::string caps; | |
736 | ||
737 | RGWUserAdminOpState op_state; | |
738 | ||
739 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
740 | rgw_user uid(uid_str); | |
741 | ||
742 | RESTArgs::get_string(s, "user-caps", caps, &caps); | |
743 | ||
744 | op_state.set_user_id(uid); | |
745 | op_state.set_caps(caps); | |
746 | ||
9f95a23c TL |
747 | if (!store->svc()->zone->is_meta_master()) { |
748 | bufferlist data; | |
749 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
750 | if (op_ret < 0) { | |
751 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
752 | return; | |
753 | } | |
754 | } | |
7c673cae FG |
755 | http_ret = RGWUserAdminOp_Caps::add(store, op_state, flusher); |
756 | } | |
757 | ||
758 | class RGWOp_Caps_Remove : public RGWRESTOp { | |
759 | ||
760 | public: | |
761 | RGWOp_Caps_Remove() {} | |
762 | ||
9f95a23c | 763 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
764 | return caps.check_cap("users", RGW_CAP_WRITE); |
765 | } | |
766 | ||
767 | void execute() override; | |
768 | ||
11fdf7f2 | 769 | const char* name() const override { return "remove_user_caps"; } |
7c673cae FG |
770 | }; |
771 | ||
772 | void RGWOp_Caps_Remove::execute() | |
773 | { | |
774 | std::string uid_str; | |
775 | std::string caps; | |
776 | ||
777 | RGWUserAdminOpState op_state; | |
778 | ||
779 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
780 | rgw_user uid(uid_str); | |
781 | ||
782 | RESTArgs::get_string(s, "user-caps", caps, &caps); | |
783 | ||
784 | op_state.set_user_id(uid); | |
785 | op_state.set_caps(caps); | |
786 | ||
9f95a23c TL |
787 | if (!store->svc()->zone->is_meta_master()) { |
788 | bufferlist data; | |
789 | op_ret = forward_request_to_master(s, nullptr, store, data, nullptr); | |
790 | if (op_ret < 0) { | |
791 | ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; | |
792 | return; | |
793 | } | |
794 | } | |
7c673cae FG |
795 | http_ret = RGWUserAdminOp_Caps::remove(store, op_state, flusher); |
796 | } | |
797 | ||
798 | struct UserQuotas { | |
799 | RGWQuotaInfo bucket_quota; | |
800 | RGWQuotaInfo user_quota; | |
801 | ||
802 | UserQuotas() {} | |
803 | ||
804 | explicit UserQuotas(RGWUserInfo& info) : bucket_quota(info.bucket_quota), | |
805 | user_quota(info.user_quota) {} | |
806 | ||
807 | void dump(Formatter *f) const { | |
808 | encode_json("bucket_quota", bucket_quota, f); | |
809 | encode_json("user_quota", user_quota, f); | |
810 | } | |
811 | void decode_json(JSONObj *obj) { | |
812 | JSONDecoder::decode_json("bucket_quota", bucket_quota, obj); | |
813 | JSONDecoder::decode_json("user_quota", user_quota, obj); | |
814 | } | |
815 | }; | |
816 | ||
817 | class RGWOp_Quota_Info : public RGWRESTOp { | |
818 | ||
819 | public: | |
820 | RGWOp_Quota_Info() {} | |
821 | ||
9f95a23c | 822 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
823 | return caps.check_cap("users", RGW_CAP_READ); |
824 | } | |
825 | ||
826 | void execute() override; | |
827 | ||
11fdf7f2 | 828 | const char* name() const override { return "get_quota_info"; } |
7c673cae FG |
829 | }; |
830 | ||
831 | ||
832 | void RGWOp_Quota_Info::execute() | |
833 | { | |
834 | RGWUserAdminOpState op_state; | |
835 | ||
836 | std::string uid_str; | |
837 | std::string quota_type; | |
838 | ||
839 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
840 | RESTArgs::get_string(s, "quota-type", quota_type, "a_type); | |
841 | ||
842 | if (uid_str.empty()) { | |
843 | http_ret = -EINVAL; | |
844 | return; | |
845 | } | |
846 | ||
847 | rgw_user uid(uid_str); | |
848 | ||
849 | bool show_all = quota_type.empty(); | |
850 | bool show_bucket = show_all || (quota_type == "bucket"); | |
851 | bool show_user = show_all || (quota_type == "user"); | |
852 | ||
853 | if (!(show_all || show_bucket || show_user)) { | |
854 | http_ret = -EINVAL; | |
855 | return; | |
856 | } | |
857 | ||
858 | op_state.set_user_id(uid); | |
859 | ||
860 | RGWUser user; | |
861 | http_ret = user.init(store, op_state); | |
862 | if (http_ret < 0) | |
863 | return; | |
864 | ||
224ce89b WB |
865 | if (!op_state.has_existing_user()) { |
866 | http_ret = -ERR_NO_SUCH_USER; | |
867 | return; | |
868 | } | |
869 | ||
7c673cae FG |
870 | RGWUserInfo info; |
871 | string err_msg; | |
872 | http_ret = user.info(info, &err_msg); | |
873 | if (http_ret < 0) | |
874 | return; | |
875 | ||
876 | flusher.start(0); | |
877 | if (show_all) { | |
878 | UserQuotas quotas(info); | |
879 | encode_json("quota", quotas, s->formatter); | |
880 | } else if (show_user) { | |
881 | encode_json("user_quota", info.user_quota, s->formatter); | |
882 | } else { | |
883 | encode_json("bucket_quota", info.bucket_quota, s->formatter); | |
884 | } | |
885 | ||
886 | flusher.flush(); | |
887 | } | |
888 | ||
889 | class RGWOp_Quota_Set : public RGWRESTOp { | |
890 | ||
891 | public: | |
892 | RGWOp_Quota_Set() {} | |
893 | ||
9f95a23c | 894 | int check_caps(const RGWUserCaps& caps) override { |
7c673cae FG |
895 | return caps.check_cap("users", RGW_CAP_WRITE); |
896 | } | |
897 | ||
898 | void execute() override; | |
899 | ||
11fdf7f2 | 900 | const char* name() const override { return "set_quota_info"; } |
7c673cae FG |
901 | }; |
902 | ||
903 | /** | |
904 | * set quota | |
905 | * | |
906 | * two different ways to set the quota info: as json struct in the message body or via http params. | |
907 | * | |
908 | * as json: | |
909 | * | |
910 | * PUT /admin/user?uid=<uid>["a-type=<type>] | |
911 | * | |
912 | * whereas quota-type is optional and is either user, or bucket | |
913 | * | |
914 | * if quota-type is not specified then we expect to get a structure that contains both quotas, | |
915 | * otherwise we'll only get the relevant configuration. | |
916 | * | |
917 | * E.g., if quota type not specified: | |
918 | * { | |
919 | * "user_quota" : { | |
920 | * "max_size_kb" : 4096, | |
921 | * "max_objects" : -1, | |
922 | * "enabled" : false | |
923 | * }, | |
924 | * "bucket_quota" : { | |
925 | * "max_size_kb" : 1024, | |
926 | * "max_objects" : -1, | |
927 | * "enabled" : true | |
928 | * } | |
929 | * } | |
930 | * | |
931 | * | |
932 | * or if quota type is specified: | |
933 | * { | |
934 | * "max_size_kb" : 4096, | |
935 | * "max_objects" : -1, | |
936 | * "enabled" : false | |
937 | * } | |
938 | * | |
939 | * Another option is not to pass any body and set the following http params: | |
940 | * | |
941 | * | |
942 | * max-size-kb=<size> | |
943 | * max-objects=<max objects> | |
944 | * enabled[={true,false}] | |
945 | * | |
946 | * all params are optionals and default to the current settings. With this type of configuration the | |
947 | * quota-type param is mandatory. | |
948 | * | |
949 | */ | |
950 | ||
951 | void RGWOp_Quota_Set::execute() | |
952 | { | |
953 | RGWUserAdminOpState op_state; | |
954 | ||
955 | std::string uid_str; | |
956 | std::string quota_type; | |
957 | ||
958 | RESTArgs::get_string(s, "uid", uid_str, &uid_str); | |
959 | RESTArgs::get_string(s, "quota-type", quota_type, "a_type); | |
960 | ||
961 | if (uid_str.empty()) { | |
962 | http_ret = -EINVAL; | |
963 | return; | |
964 | } | |
965 | ||
966 | rgw_user uid(uid_str); | |
967 | ||
968 | bool set_all = quota_type.empty(); | |
969 | bool set_bucket = set_all || (quota_type == "bucket"); | |
970 | bool set_user = set_all || (quota_type == "user"); | |
971 | ||
972 | if (!(set_all || set_bucket || set_user)) { | |
973 | ldout(store->ctx(), 20) << "invalid quota type" << dendl; | |
974 | http_ret = -EINVAL; | |
975 | return; | |
976 | } | |
977 | ||
978 | bool use_http_params; | |
979 | ||
980 | if (s->content_length > 0) { | |
981 | use_http_params = false; | |
982 | } else { | |
983 | const char *encoding = s->info.env->get("HTTP_TRANSFER_ENCODING"); | |
984 | use_http_params = (!encoding || strcmp(encoding, "chunked") != 0); | |
985 | } | |
986 | ||
987 | if (use_http_params && set_all) { | |
988 | ldout(store->ctx(), 20) << "quota type was not specified, can't set all quotas via http headers" << dendl; | |
989 | http_ret = -EINVAL; | |
990 | return; | |
991 | } | |
992 | ||
993 | op_state.set_user_id(uid); | |
994 | ||
995 | RGWUser user; | |
996 | http_ret = user.init(store, op_state); | |
997 | if (http_ret < 0) { | |
998 | ldout(store->ctx(), 20) << "failed initializing user info: " << http_ret << dendl; | |
999 | return; | |
1000 | } | |
1001 | ||
224ce89b WB |
1002 | if (!op_state.has_existing_user()) { |
1003 | http_ret = -ERR_NO_SUCH_USER; | |
1004 | return; | |
1005 | } | |
1006 | ||
7c673cae FG |
1007 | #define QUOTA_INPUT_MAX_LEN 1024 |
1008 | if (set_all) { | |
1009 | UserQuotas quotas; | |
1010 | ||
1011 | if ((http_ret = rgw_rest_get_json_input(store->ctx(), s, quotas, QUOTA_INPUT_MAX_LEN, NULL)) < 0) { | |
1012 | ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; | |
1013 | return; | |
1014 | } | |
1015 | ||
1016 | op_state.set_user_quota(quotas.user_quota); | |
1017 | op_state.set_bucket_quota(quotas.bucket_quota); | |
1018 | } else { | |
1019 | RGWQuotaInfo quota; | |
1020 | ||
1021 | if (!use_http_params) { | |
1022 | bool empty; | |
1023 | http_ret = rgw_rest_get_json_input(store->ctx(), s, quota, QUOTA_INPUT_MAX_LEN, &empty); | |
1024 | if (http_ret < 0) { | |
1025 | ldout(store->ctx(), 20) << "failed to retrieve input" << dendl; | |
1026 | if (!empty) | |
1027 | return; | |
1028 | ||
1029 | /* was probably chunked input, but no content provided, configure via http params */ | |
1030 | use_http_params = true; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | if (use_http_params) { | |
1035 | RGWUserInfo info; | |
1036 | string err_msg; | |
1037 | http_ret = user.info(info, &err_msg); | |
1038 | if (http_ret < 0) { | |
1039 | ldout(store->ctx(), 20) << "failed to get user info: " << http_ret << dendl; | |
1040 | return; | |
1041 | } | |
1042 | RGWQuotaInfo *old_quota; | |
1043 | if (set_user) { | |
1044 | old_quota = &info.user_quota; | |
1045 | } else { | |
1046 | old_quota = &info.bucket_quota; | |
1047 | } | |
1048 | ||
7c673cae | 1049 | RESTArgs::get_int64(s, "max-objects", old_quota->max_objects, "a.max_objects); |
f64942e4 AA |
1050 | RESTArgs::get_int64(s, "max-size", old_quota->max_size, "a.max_size); |
1051 | int64_t max_size_kb; | |
1052 | bool has_max_size_kb = false; | |
1053 | RESTArgs::get_int64(s, "max-size-kb", 0, &max_size_kb, &has_max_size_kb); | |
1054 | if (has_max_size_kb) { | |
1055 | quota.max_size = max_size_kb * 1024; | |
1056 | } | |
7c673cae FG |
1057 | RESTArgs::get_bool(s, "enabled", old_quota->enabled, "a.enabled); |
1058 | } | |
1059 | ||
1060 | if (set_user) { | |
1061 | op_state.set_user_quota(quota); | |
1062 | } else { | |
1063 | op_state.set_bucket_quota(quota); | |
1064 | } | |
1065 | } | |
1066 | ||
1067 | string err; | |
1068 | http_ret = user.modify(op_state, &err); | |
1069 | if (http_ret < 0) { | |
1070 | ldout(store->ctx(), 20) << "failed updating user info: " << http_ret << ": " << err << dendl; | |
1071 | return; | |
1072 | } | |
1073 | } | |
1074 | ||
1075 | RGWOp *RGWHandler_User::op_get() | |
1076 | { | |
1077 | if (s->info.args.sub_resource_exists("quota")) | |
1078 | return new RGWOp_Quota_Info; | |
1079 | ||
11fdf7f2 TL |
1080 | if (s->info.args.sub_resource_exists("list")) |
1081 | return new RGWOp_User_List; | |
1082 | ||
7c673cae FG |
1083 | return new RGWOp_User_Info; |
1084 | } | |
1085 | ||
1086 | RGWOp *RGWHandler_User::op_put() | |
1087 | { | |
1088 | if (s->info.args.sub_resource_exists("subuser")) | |
1089 | return new RGWOp_Subuser_Create; | |
1090 | ||
1091 | if (s->info.args.sub_resource_exists("key")) | |
1092 | return new RGWOp_Key_Create; | |
1093 | ||
1094 | if (s->info.args.sub_resource_exists("caps")) | |
1095 | return new RGWOp_Caps_Add; | |
1096 | ||
1097 | if (s->info.args.sub_resource_exists("quota")) | |
1098 | return new RGWOp_Quota_Set; | |
1099 | ||
1100 | return new RGWOp_User_Create; | |
1101 | } | |
1102 | ||
1103 | RGWOp *RGWHandler_User::op_post() | |
1104 | { | |
1105 | if (s->info.args.sub_resource_exists("subuser")) | |
1106 | return new RGWOp_Subuser_Modify; | |
1107 | ||
1108 | return new RGWOp_User_Modify; | |
1109 | } | |
1110 | ||
1111 | RGWOp *RGWHandler_User::op_delete() | |
1112 | { | |
1113 | if (s->info.args.sub_resource_exists("subuser")) | |
1114 | return new RGWOp_Subuser_Remove; | |
1115 | ||
1116 | if (s->info.args.sub_resource_exists("key")) | |
1117 | return new RGWOp_Key_Remove; | |
1118 | ||
1119 | if (s->info.args.sub_resource_exists("caps")) | |
1120 | return new RGWOp_Caps_Remove; | |
1121 | ||
1122 | return new RGWOp_User_Remove; | |
1123 | } | |
1124 |