]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_acl_s3.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / rgw / rgw_acl_s3.cc
CommitLineData
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 <string.h>
5
6#include <iostream>
7#include <map>
8
9#include "include/types.h"
10
11#include "rgw_acl_s3.h"
12#include "rgw_user.h"
13
14#define dout_subsys ceph_subsys_rgw
15
7c673cae
FG
16
17
18#define RGW_URI_ALL_USERS "http://acs.amazonaws.com/groups/global/AllUsers"
19#define RGW_URI_AUTH_USERS "http://acs.amazonaws.com/groups/global/AuthenticatedUsers"
20
21static string rgw_uri_all_users = RGW_URI_ALL_USERS;
22static string rgw_uri_auth_users = RGW_URI_AUTH_USERS;
23
24void ACLPermission_S3::to_xml(ostream& out)
25{
26 if ((flags & RGW_PERM_FULL_CONTROL) == RGW_PERM_FULL_CONTROL) {
27 out << "<Permission>FULL_CONTROL</Permission>";
28 } else {
29 if (flags & RGW_PERM_READ)
30 out << "<Permission>READ</Permission>";
31 if (flags & RGW_PERM_WRITE)
32 out << "<Permission>WRITE</Permission>";
33 if (flags & RGW_PERM_READ_ACP)
34 out << "<Permission>READ_ACP</Permission>";
35 if (flags & RGW_PERM_WRITE_ACP)
36 out << "<Permission>WRITE_ACP</Permission>";
37 }
38}
39
40bool ACLPermission_S3::
41xml_end(const char *el)
42{
43 const char *s = data.c_str();
44 if (strcasecmp(s, "READ") == 0) {
45 flags |= RGW_PERM_READ;
46 return true;
47 } else if (strcasecmp(s, "WRITE") == 0) {
48 flags |= RGW_PERM_WRITE;
49 return true;
50 } else if (strcasecmp(s, "READ_ACP") == 0) {
51 flags |= RGW_PERM_READ_ACP;
52 return true;
53 } else if (strcasecmp(s, "WRITE_ACP") == 0) {
54 flags |= RGW_PERM_WRITE_ACP;
55 return true;
56 } else if (strcasecmp(s, "FULL_CONTROL") == 0) {
57 flags |= RGW_PERM_FULL_CONTROL;
58 return true;
59 }
60 return false;
61}
62
63
64class ACLGranteeType_S3 {
65public:
66 static const char *to_string(ACLGranteeType& type) {
67 switch (type.get_type()) {
68 case ACL_TYPE_CANON_USER:
69 return "CanonicalUser";
70 case ACL_TYPE_EMAIL_USER:
71 return "AmazonCustomerByEmail";
72 case ACL_TYPE_GROUP:
73 return "Group";
74 default:
75 return "unknown";
76 }
77 }
78
79 static void set(const char *s, ACLGranteeType& type) {
80 if (!s) {
81 type.set(ACL_TYPE_UNKNOWN);
82 return;
83 }
84 if (strcmp(s, "CanonicalUser") == 0)
85 type.set(ACL_TYPE_CANON_USER);
86 else if (strcmp(s, "AmazonCustomerByEmail") == 0)
87 type.set(ACL_TYPE_EMAIL_USER);
88 else if (strcmp(s, "Group") == 0)
89 type.set(ACL_TYPE_GROUP);
90 else
91 type.set(ACL_TYPE_UNKNOWN);
92 }
93};
94
95class ACLID_S3 : public XMLObj
96{
97public:
98 ACLID_S3() {}
99 ~ACLID_S3() override {}
100 string& to_str() { return data; }
101};
102
103class ACLURI_S3 : public XMLObj
104{
105public:
106 ACLURI_S3() {}
107 ~ACLURI_S3() override {}
108};
109
110class ACLEmail_S3 : public XMLObj
111{
112public:
113 ACLEmail_S3() {}
114 ~ACLEmail_S3() override {}
115};
116
117class ACLDisplayName_S3 : public XMLObj
118{
119public:
120 ACLDisplayName_S3() {}
121 ~ACLDisplayName_S3() override {}
122};
123
124bool ACLOwner_S3::xml_end(const char *el) {
125 ACLID_S3 *acl_id = static_cast<ACLID_S3 *>(find_first("ID"));
126 ACLID_S3 *acl_name = static_cast<ACLID_S3 *>(find_first("DisplayName"));
127
128 // ID is mandatory
129 if (!acl_id)
130 return false;
131 id = acl_id->get_data();
132
133 // DisplayName is optional
134 if (acl_name)
135 display_name = acl_name->get_data();
136 else
137 display_name = "";
138
139 return true;
140}
141
142void ACLOwner_S3::to_xml(ostream& out) {
143 string s;
144 id.to_str(s);
145 if (s.empty())
146 return;
147 out << "<Owner>" << "<ID>" << s << "</ID>";
148 if (!display_name.empty())
149 out << "<DisplayName>" << display_name << "</DisplayName>";
150 out << "</Owner>";
151}
152
153bool ACLGrant_S3::xml_end(const char *el) {
154 ACLGrantee_S3 *acl_grantee;
155 ACLID_S3 *acl_id;
156 ACLURI_S3 *acl_uri;
157 ACLEmail_S3 *acl_email;
158 ACLPermission_S3 *acl_permission;
159 ACLDisplayName_S3 *acl_name;
160 string uri;
161
162 acl_grantee = static_cast<ACLGrantee_S3 *>(find_first("Grantee"));
163 if (!acl_grantee)
164 return false;
165 string type_str;
166 if (!acl_grantee->get_attr("xsi:type", type_str))
167 return false;
168 ACLGranteeType_S3::set(type_str.c_str(), type);
169
170 acl_permission = static_cast<ACLPermission_S3 *>(find_first("Permission"));
171 if (!acl_permission)
172 return false;
173
174 permission = *acl_permission;
175
176 id.clear();
177 name.clear();
178 email.clear();
179
180 switch (type.get_type()) {
181 case ACL_TYPE_CANON_USER:
182 acl_id = static_cast<ACLID_S3 *>(acl_grantee->find_first("ID"));
183 if (!acl_id)
184 return false;
185 id = acl_id->to_str();
186 acl_name = static_cast<ACLDisplayName_S3 *>(acl_grantee->find_first("DisplayName"));
187 if (acl_name)
188 name = acl_name->get_data();
189 break;
190 case ACL_TYPE_GROUP:
191 acl_uri = static_cast<ACLURI_S3 *>(acl_grantee->find_first("URI"));
192 if (!acl_uri)
193 return false;
194 uri = acl_uri->get_data();
195 group = uri_to_group(uri);
196 break;
197 case ACL_TYPE_EMAIL_USER:
198 acl_email = static_cast<ACLEmail_S3 *>(acl_grantee->find_first("EmailAddress"));
199 if (!acl_email)
200 return false;
201 email = acl_email->get_data();
202 break;
203 default:
204 // unknown user type
205 return false;
206 };
207 return true;
208}
209
210void ACLGrant_S3::to_xml(CephContext *cct, ostream& out) {
211 ACLPermission_S3& perm = static_cast<ACLPermission_S3 &>(permission);
212
213 /* only show s3 compatible permissions */
214 if (!(perm.get_permissions() & RGW_PERM_ALL_S3))
215 return;
216
217 string uri;
218
219 out << "<Grant>" <<
220 "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"" << ACLGranteeType_S3::to_string(type) << "\">";
221 switch (type.get_type()) {
222 case ACL_TYPE_CANON_USER:
223 out << "<ID>" << id << "</ID>";
224 if (name.size()) {
225 out << "<DisplayName>" << name << "</DisplayName>";
226 }
227 break;
228 case ACL_TYPE_EMAIL_USER:
229 out << "<EmailAddress>" << email << "</EmailAddress>";
230 break;
231 case ACL_TYPE_GROUP:
232 if (!group_to_uri(group, uri)) {
233 ldout(cct, 0) << "ERROR: group_to_uri failed with group=" << (int)group << dendl;
234 break;
235 }
236 out << "<URI>" << uri << "</URI>";
237 break;
238 default:
239 break;
240 }
241 out << "</Grantee>";
242 perm.to_xml(out);
243 out << "</Grant>";
244}
245
246bool ACLGrant_S3::group_to_uri(ACLGroupTypeEnum group, string& uri)
247{
248 switch (group) {
249 case ACL_GROUP_ALL_USERS:
250 uri = rgw_uri_all_users;
251 return true;
252 case ACL_GROUP_AUTHENTICATED_USERS:
253 uri = rgw_uri_auth_users;
254 return true;
255 default:
256 return false;
257 }
258}
259
260bool RGWAccessControlList_S3::xml_end(const char *el) {
261 XMLObjIter iter = find("Grant");
262 ACLGrant_S3 *grant = static_cast<ACLGrant_S3 *>(iter.get_next());
263 while (grant) {
264 add_grant(grant);
265 grant = static_cast<ACLGrant_S3 *>(iter.get_next());
266 }
267 return true;
268}
269
270void RGWAccessControlList_S3::to_xml(ostream& out) {
271 multimap<string, ACLGrant>::iterator iter;
272 out << "<AccessControlList>";
273 for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
274 ACLGrant_S3& grant = static_cast<ACLGrant_S3 &>(iter->second);
275 grant.to_xml(cct, out);
276 }
277 out << "</AccessControlList>";
278}
279
280struct s3_acl_header {
281 int rgw_perm;
282 const char *http_header;
283};
284
31f18b77 285static const char *get_acl_header(const RGWEnv *env,
7c673cae
FG
286 const struct s3_acl_header *perm)
287{
288 const char *header = perm->http_header;
289
290 return env->get(header, NULL);
291}
292
9f95a23c 293static int parse_grantee_str(RGWUserCtl *user_ctl, string& grantee_str,
7c673cae
FG
294 const struct s3_acl_header *perm, ACLGrant& grant)
295{
296 string id_type, id_val_quoted;
297 int rgw_perm = perm->rgw_perm;
298 int ret;
299
300 RGWUserInfo info;
301
302 ret = parse_key_value(grantee_str, id_type, id_val_quoted);
303 if (ret < 0)
304 return ret;
305
306 string id_val = rgw_trim_quotes(id_val_quoted);
307
308 if (strcasecmp(id_type.c_str(), "emailAddress") == 0) {
9f95a23c 309 ret = user_ctl->get_info_by_email(id_val, &info, null_yield);
7c673cae
FG
310 if (ret < 0)
311 return ret;
312
313 grant.set_canon(info.user_id, info.display_name, rgw_perm);
314 } else if (strcasecmp(id_type.c_str(), "id") == 0) {
315 rgw_user user(id_val);
9f95a23c 316 ret = user_ctl->get_info_by_uid(user, &info, null_yield);
7c673cae
FG
317 if (ret < 0)
318 return ret;
319
320 grant.set_canon(info.user_id, info.display_name, rgw_perm);
321 } else if (strcasecmp(id_type.c_str(), "uri") == 0) {
322 ACLGroupTypeEnum gid = grant.uri_to_group(id_val);
323 if (gid == ACL_GROUP_NONE)
324 return -EINVAL;
325
326 grant.set_group(gid, rgw_perm);
327 } else {
328 return -EINVAL;
329 }
330
331 return 0;
332}
333
9f95a23c 334static int parse_acl_header(RGWUserCtl *user_ctl, const RGWEnv *env,
7c673cae
FG
335 const struct s3_acl_header *perm, std::list<ACLGrant>& _grants)
336{
337 std::list<string> grantees;
338 std::string hacl_str;
339
340 const char *hacl = get_acl_header(env, perm);
341 if (hacl == NULL)
342 return 0;
343
344 hacl_str = hacl;
345 get_str_list(hacl_str, ",", grantees);
346
347 for (list<string>::iterator it = grantees.begin(); it != grantees.end(); ++it) {
348 ACLGrant grant;
9f95a23c 349 int ret = parse_grantee_str(user_ctl, *it, perm, grant);
7c673cae
FG
350 if (ret < 0)
351 return ret;
352
353 _grants.push_back(grant);
354 }
355
356 return 0;
357}
358
359int RGWAccessControlList_S3::create_canned(ACLOwner& owner, ACLOwner& bucket_owner, const string& canned_acl)
360{
361 acl_user_map.clear();
362 grant_map.clear();
363
364 ACLGrant owner_grant;
365
366 rgw_user bid = bucket_owner.get_id();
367 string bname = bucket_owner.get_display_name();
368
369 /* owner gets full control */
370 owner_grant.set_canon(owner.get_id(), owner.get_display_name(), RGW_PERM_FULL_CONTROL);
371 add_grant(&owner_grant);
372
373 if (canned_acl.size() == 0 || canned_acl.compare("private") == 0) {
374 return 0;
375 }
376
377 ACLGrant bucket_owner_grant;
378 ACLGrant group_grant;
379 if (canned_acl.compare("public-read") == 0) {
380 group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_READ);
381 add_grant(&group_grant);
382 } else if (canned_acl.compare("public-read-write") == 0) {
383 group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_READ);
384 add_grant(&group_grant);
385 group_grant.set_group(ACL_GROUP_ALL_USERS, RGW_PERM_WRITE);
386 add_grant(&group_grant);
387 } else if (canned_acl.compare("authenticated-read") == 0) {
388 group_grant.set_group(ACL_GROUP_AUTHENTICATED_USERS, RGW_PERM_READ);
389 add_grant(&group_grant);
390 } else if (canned_acl.compare("bucket-owner-read") == 0) {
391 bucket_owner_grant.set_canon(bid, bname, RGW_PERM_READ);
392 if (bid.compare(owner.get_id()) != 0)
393 add_grant(&bucket_owner_grant);
394 } else if (canned_acl.compare("bucket-owner-full-control") == 0) {
395 bucket_owner_grant.set_canon(bid, bname, RGW_PERM_FULL_CONTROL);
396 if (bid.compare(owner.get_id()) != 0)
397 add_grant(&bucket_owner_grant);
398 } else {
399 return -EINVAL;
400 }
401
402 return 0;
403}
404
405int RGWAccessControlList_S3::create_from_grants(std::list<ACLGrant>& grants)
406{
407 if (grants.empty())
408 return -EINVAL;
409
410 acl_user_map.clear();
411 grant_map.clear();
412
413 for (std::list<ACLGrant>::iterator it = grants.begin(); it != grants.end(); ++it) {
414 ACLGrant g = *it;
415 add_grant(&g);
416 }
417
418 return 0;
419}
420
421bool RGWAccessControlPolicy_S3::xml_end(const char *el) {
422 RGWAccessControlList_S3 *s3acl =
423 static_cast<RGWAccessControlList_S3 *>(find_first("AccessControlList"));
424 if (!s3acl)
425 return false;
426
427 acl = *s3acl;
428
429 ACLOwner *owner_p = static_cast<ACLOwner_S3 *>(find_first("Owner"));
430 if (!owner_p)
431 return false;
432 owner = *owner_p;
433 return true;
434}
435
436void RGWAccessControlPolicy_S3::to_xml(ostream& out) {
437 out << "<AccessControlPolicy xmlns=\"" << XMLNS_AWS_S3 << "\">";
438 ACLOwner_S3& _owner = static_cast<ACLOwner_S3 &>(owner);
439 RGWAccessControlList_S3& _acl = static_cast<RGWAccessControlList_S3 &>(acl);
440 _owner.to_xml(out);
441 _acl.to_xml(out);
442 out << "</AccessControlPolicy>";
443}
444
445static const s3_acl_header acl_header_perms[] = {
446 {RGW_PERM_READ, "HTTP_X_AMZ_GRANT_READ"},
447 {RGW_PERM_WRITE, "HTTP_X_AMZ_GRANT_WRITE"},
448 {RGW_PERM_READ_ACP,"HTTP_X_AMZ_GRANT_READ_ACP"},
449 {RGW_PERM_WRITE_ACP, "HTTP_X_AMZ_GRANT_WRITE_ACP"},
450 {RGW_PERM_FULL_CONTROL, "HTTP_X_AMZ_GRANT_FULL_CONTROL"},
451 {0, NULL}
452};
453
9f95a23c 454int RGWAccessControlPolicy_S3::create_from_headers(RGWUserCtl *user_ctl, const RGWEnv *env, ACLOwner& _owner)
7c673cae
FG
455{
456 std::list<ACLGrant> grants;
11fdf7f2 457 int r = 0;
7c673cae
FG
458
459 for (const struct s3_acl_header *p = acl_header_perms; p->rgw_perm; p++) {
9f95a23c 460 r = parse_acl_header(user_ctl, env, p, grants);
11fdf7f2
TL
461 if (r < 0) {
462 return r;
463 }
7c673cae
FG
464 }
465
466 RGWAccessControlList_S3& _acl = static_cast<RGWAccessControlList_S3 &>(acl);
11fdf7f2 467 r = _acl.create_from_grants(grants);
7c673cae
FG
468
469 owner = _owner;
470
471 return r;
472}
473
474/*
475 can only be called on object that was parsed
476 */
9f95a23c
TL
477int RGWAccessControlPolicy_S3::rebuild(RGWUserCtl *user_ctl, ACLOwner *owner, RGWAccessControlPolicy& dest,
478 std::string &err_msg)
7c673cae
FG
479{
480 if (!owner)
481 return -EINVAL;
482
483 ACLOwner *requested_owner = static_cast<ACLOwner_S3 *>(find_first("Owner"));
484 if (requested_owner) {
485 rgw_user& requested_id = requested_owner->get_id();
486 if (!requested_id.empty() && requested_id.compare(owner->get_id()) != 0)
487 return -EPERM;
488 }
489
490 RGWUserInfo owner_info;
9f95a23c 491 if (user_ctl->get_info_by_uid(owner->get_id(), &owner_info, null_yield) < 0) {
7c673cae 492 ldout(cct, 10) << "owner info does not exist" << dendl;
9f95a23c 493 err_msg = "Invalid id";
7c673cae
FG
494 return -EINVAL;
495 }
496 ACLOwner& dest_owner = dest.get_owner();
497 dest_owner.set_id(owner->get_id());
498 dest_owner.set_name(owner_info.display_name);
499
500 ldout(cct, 20) << "owner id=" << owner->get_id() << dendl;
501 ldout(cct, 20) << "dest owner id=" << dest.get_owner().get_id() << dendl;
502
503 RGWAccessControlList& dst_acl = dest.get_acl();
504
505 multimap<string, ACLGrant>& grant_map = acl.get_grant_map();
506 multimap<string, ACLGrant>::iterator iter;
507 for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
508 ACLGrant& src_grant = iter->second;
509 ACLGranteeType& type = src_grant.get_type();
510 ACLGrant new_grant;
511 bool grant_ok = false;
512 rgw_user uid;
513 RGWUserInfo grant_user;
514 switch (type.get_type()) {
515 case ACL_TYPE_EMAIL_USER:
516 {
517 string email;
518 rgw_user u;
519 if (!src_grant.get_id(u)) {
520 ldout(cct, 0) << "ERROR: src_grant.get_id() failed" << dendl;
521 return -EINVAL;
522 }
523 email = u.id;
524 ldout(cct, 10) << "grant user email=" << email << dendl;
9f95a23c 525 if (user_ctl->get_info_by_email(email, &grant_user, null_yield) < 0) {
7c673cae 526 ldout(cct, 10) << "grant user email not found or other error" << dendl;
9f95a23c 527 err_msg = "The e-mail address you provided does not match any account on record.";
7c673cae
FG
528 return -ERR_UNRESOLVABLE_EMAIL;
529 }
530 uid = grant_user.user_id;
531 }
532 case ACL_TYPE_CANON_USER:
533 {
534 if (type.get_type() == ACL_TYPE_CANON_USER) {
535 if (!src_grant.get_id(uid)) {
536 ldout(cct, 0) << "ERROR: src_grant.get_id() failed" << dendl;
9f95a23c 537 err_msg = "Invalid id";
7c673cae
FG
538 return -EINVAL;
539 }
540 }
541
9f95a23c 542 if (grant_user.user_id.empty() && user_ctl->get_info_by_uid(uid, &grant_user, null_yield) < 0) {
7c673cae 543 ldout(cct, 10) << "grant user does not exist:" << uid << dendl;
9f95a23c 544 err_msg = "Invalid id";
7c673cae
FG
545 return -EINVAL;
546 } else {
547 ACLPermission& perm = src_grant.get_permission();
548 new_grant.set_canon(uid, grant_user.display_name, perm.get_permissions());
549 grant_ok = true;
550 rgw_user new_id;
551 new_grant.get_id(new_id);
552 ldout(cct, 10) << "new grant: " << new_id << ":" << grant_user.display_name << dendl;
553 }
554 }
555 break;
556 case ACL_TYPE_GROUP:
557 {
558 string uri;
559 if (ACLGrant_S3::group_to_uri(src_grant.get_group(), uri)) {
560 new_grant = src_grant;
561 grant_ok = true;
562 ldout(cct, 10) << "new grant: " << uri << dendl;
563 } else {
564 ldout(cct, 10) << "bad grant group:" << (int)src_grant.get_group() << dendl;
9f95a23c 565 err_msg = "Invalid group uri";
7c673cae
FG
566 return -EINVAL;
567 }
568 }
569 default:
570 break;
571 }
572 if (grant_ok) {
573 dst_acl.add_grant(&new_grant);
574 }
575 }
576
577 return 0;
578}
579
580bool RGWAccessControlPolicy_S3::compare_group_name(string& id, ACLGroupTypeEnum group)
581{
582 switch (group) {
583 case ACL_GROUP_ALL_USERS:
584 return (id.compare(RGW_USER_ANON_ID) == 0);
585 case ACL_GROUP_AUTHENTICATED_USERS:
586 return (id.compare(rgw_uri_auth_users) == 0);
587 default:
588 return id.empty();
589 }
590
591 // shouldn't get here
592 return false;
593}
594
595XMLObj *RGWACLXMLParser_S3::alloc_obj(const char *el)
596{
597 XMLObj * obj = NULL;
598 if (strcmp(el, "AccessControlPolicy") == 0) {
599 obj = new RGWAccessControlPolicy_S3(cct);
600 } else if (strcmp(el, "Owner") == 0) {
601 obj = new ACLOwner_S3();
602 } else if (strcmp(el, "AccessControlList") == 0) {
603 obj = new RGWAccessControlList_S3(cct);
604 } else if (strcmp(el, "ID") == 0) {
605 obj = new ACLID_S3();
606 } else if (strcmp(el, "DisplayName") == 0) {
607 obj = new ACLDisplayName_S3();
608 } else if (strcmp(el, "Grant") == 0) {
609 obj = new ACLGrant_S3();
610 } else if (strcmp(el, "Grantee") == 0) {
611 obj = new ACLGrantee_S3();
612 } else if (strcmp(el, "Permission") == 0) {
613 obj = new ACLPermission_S3();
614 } else if (strcmp(el, "URI") == 0) {
615 obj = new ACLURI_S3();
616 } else if (strcmp(el, "EmailAddress") == 0) {
617 obj = new ACLEmail_S3();
618 }
619
620 return obj;
621}
622