summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/rgw/rgw_acl.cc442
1 files changed, 442 insertions, 0 deletions
diff --git a/src/rgw/rgw_acl.cc b/src/rgw/rgw_acl.cc
new file mode 100644
index 000000000..f32a73f26
--- /dev/null
+++ b/src/rgw/rgw_acl.cc
@@ -0,0 +1,442 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab ft=cpp
+
+#include <string.h>
+
+#include <iostream>
+#include <map>
+
+#include "include/types.h"
+
+#include "common/Formatter.h"
+
+#include "rgw_acl.h"
+#include "rgw_acl_s3.h"
+#include "rgw_user.h"
+
+#define dout_subsys ceph_subsys_rgw
+
+using namespace std;
+
+bool operator==(const ACLPermission& lhs, const ACLPermission& rhs) {
+ return lhs.flags == rhs.flags;
+}
+bool operator!=(const ACLPermission& lhs, const ACLPermission& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator==(const ACLGranteeType& lhs, const ACLGranteeType& rhs) {
+ return lhs.type == rhs.type;
+}
+bool operator!=(const ACLGranteeType& lhs, const ACLGranteeType& rhs) {
+ return lhs.type != rhs.type;
+}
+
+bool operator==(const ACLGrant& lhs, const ACLGrant& rhs) {
+ return lhs.type == rhs.type && lhs.id == rhs.id
+ && lhs.email == rhs.email && lhs.permission == rhs.permission
+ && lhs.name == rhs.name && lhs.group == rhs.group
+ && lhs.url_spec == rhs.url_spec;
+}
+bool operator!=(const ACLGrant& lhs, const ACLGrant& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator==(const ACLReferer& lhs, const ACLReferer& rhs) {
+ return lhs.url_spec == rhs.url_spec && lhs.perm == rhs.perm;
+}
+bool operator!=(const ACLReferer& lhs, const ACLReferer& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator==(const RGWAccessControlList& lhs,
+ const RGWAccessControlList& rhs) {
+ return lhs.acl_user_map == rhs.acl_user_map
+ && lhs.acl_group_map == rhs.acl_group_map
+ && lhs.referer_list == rhs.referer_list
+ && lhs.grant_map == rhs.grant_map;
+}
+bool operator!=(const RGWAccessControlList& lhs,
+ const RGWAccessControlList& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator==(const ACLOwner& lhs, const ACLOwner& rhs) {
+ return lhs.id == rhs.id && lhs.display_name == rhs.display_name;
+}
+bool operator!=(const ACLOwner& lhs, const ACLOwner& rhs) {
+ return !(lhs == rhs);
+}
+
+bool operator==(const RGWAccessControlPolicy& lhs,
+ const RGWAccessControlPolicy& rhs) {
+ return lhs.acl == rhs.acl && lhs.owner == rhs.owner;
+}
+bool operator!=(const RGWAccessControlPolicy& lhs,
+ const RGWAccessControlPolicy& rhs) {
+ return !(lhs == rhs);
+}
+
+void RGWAccessControlList::_add_grant(ACLGrant *grant)
+{
+ ACLPermission& perm = grant->get_permission();
+ ACLGranteeType& type = grant->get_type();
+ switch (type.get_type()) {
+ case ACL_TYPE_REFERER:
+ referer_list.emplace_back(grant->get_referer(), perm.get_permissions());
+
+ /* We're specially handling the Swift's .r:* as the S3 API has a similar
+ * concept and thus we can have a small portion of compatibility here. */
+ if (grant->get_referer() == RGW_REFERER_WILDCARD) {
+ acl_group_map[ACL_GROUP_ALL_USERS] |= perm.get_permissions();
+ }
+ break;
+ case ACL_TYPE_GROUP:
+ acl_group_map[grant->get_group()] |= perm.get_permissions();
+ break;
+ default:
+ {
+ rgw_user id;
+ if (!grant->get_id(id)) {
+ ldout(cct, 0) << "ERROR: grant->get_id() failed" << dendl;
+ }
+ acl_user_map[id.to_str()] |= perm.get_permissions();
+ }
+ }
+}
+
+void RGWAccessControlList::add_grant(ACLGrant *grant)
+{
+ rgw_user id;
+ grant->get_id(id); // not that this will return false for groups, but that's ok, we won't search groups
+ grant_map.insert(pair<string, ACLGrant>(id.to_str(), *grant));
+ _add_grant(grant);
+}
+
+void RGWAccessControlList::remove_canon_user_grant(rgw_user& user_id)
+{
+ auto multi_map_iter = grant_map.find(user_id.to_str());
+ if(multi_map_iter != grant_map.end()) {
+ auto grants = grant_map.equal_range(user_id.to_str());
+ grant_map.erase(grants.first, grants.second);
+ }
+
+ auto map_iter = acl_user_map.find(user_id.to_str());
+ if (map_iter != acl_user_map.end()){
+ acl_user_map.erase(map_iter);
+ }
+}
+
+uint32_t RGWAccessControlList::get_perm(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ const uint32_t perm_mask)
+{
+ ldpp_dout(dpp, 5) << "Searching permissions for identity=" << auth_identity
+ << " mask=" << perm_mask << dendl;
+
+ return perm_mask & auth_identity.get_perms_from_aclspec(dpp, acl_user_map);
+}
+
+uint32_t RGWAccessControlList::get_group_perm(const DoutPrefixProvider *dpp,
+ ACLGroupTypeEnum group,
+ const uint32_t perm_mask) const
+{
+ ldpp_dout(dpp, 5) << "Searching permissions for group=" << (int)group
+ << " mask=" << perm_mask << dendl;
+
+ const auto iter = acl_group_map.find((uint32_t)group);
+ if (iter != acl_group_map.end()) {
+ ldpp_dout(dpp, 5) << "Found permission: " << iter->second << dendl;
+ return iter->second & perm_mask;
+ }
+ ldpp_dout(dpp, 5) << "Permissions for group not found" << dendl;
+ return 0;
+}
+
+uint32_t RGWAccessControlList::get_referer_perm(const DoutPrefixProvider *dpp,
+ const uint32_t current_perm,
+ const std::string http_referer,
+ const uint32_t perm_mask)
+{
+ ldpp_dout(dpp, 5) << "Searching permissions for referer=" << http_referer
+ << " mask=" << perm_mask << dendl;
+
+ /* This function is basically a transformation from current perm to
+ * a new one that takes into consideration the Swift's HTTP referer-
+ * based ACLs. We need to go through all items to respect negative
+ * grants. */
+ uint32_t referer_perm = current_perm;
+ for (const auto& r : referer_list) {
+ if (r.is_match(http_referer)) {
+ referer_perm = r.perm;
+ }
+ }
+
+ ldpp_dout(dpp, 5) << "Found referer permission=" << referer_perm << dendl;
+ return referer_perm & perm_mask;
+}
+
+uint32_t RGWAccessControlPolicy::get_perm(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ const uint32_t perm_mask,
+ const char * const http_referer,
+ bool ignore_public_acls)
+{
+ ldpp_dout(dpp, 20) << "-- Getting permissions begin with perm_mask=" << perm_mask
+ << dendl;
+
+ uint32_t perm = acl.get_perm(dpp, auth_identity, perm_mask);
+
+ if (auth_identity.is_owner_of(owner.get_id())) {
+ perm |= perm_mask & (RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP);
+ }
+
+ if (perm == perm_mask) {
+ return perm;
+ }
+
+ /* should we continue looking up? */
+ if (!ignore_public_acls && ((perm & perm_mask) != perm_mask)) {
+ perm |= acl.get_group_perm(dpp, ACL_GROUP_ALL_USERS, perm_mask);
+
+ if (false == auth_identity.is_owner_of(rgw_user(RGW_USER_ANON_ID))) {
+ /* this is not the anonymous user */
+ perm |= acl.get_group_perm(dpp, ACL_GROUP_AUTHENTICATED_USERS, perm_mask);
+ }
+ }
+
+ /* Should we continue looking up even deeper? */
+ if (nullptr != http_referer && (perm & perm_mask) != perm_mask) {
+ perm = acl.get_referer_perm(dpp, perm, http_referer, perm_mask);
+ }
+
+ ldpp_dout(dpp, 5) << "-- Getting permissions done for identity=" << auth_identity
+ << ", owner=" << owner.get_id()
+ << ", perm=" << perm << dendl;
+
+ return perm;
+}
+
+bool RGWAccessControlPolicy::verify_permission(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ const uint32_t user_perm_mask,
+ const uint32_t perm,
+ const char * const http_referer,
+ bool ignore_public_acls)
+{
+ uint32_t test_perm = perm | RGW_PERM_READ_OBJS | RGW_PERM_WRITE_OBJS;
+
+ uint32_t policy_perm = get_perm(dpp, auth_identity, test_perm, http_referer, ignore_public_acls);
+
+ /* the swift WRITE_OBJS perm is equivalent to the WRITE obj, just
+ convert those bits. Note that these bits will only be set on
+ buckets, so the swift READ permission on bucket will allow listing
+ the bucket content */
+ if (policy_perm & RGW_PERM_WRITE_OBJS) {
+ policy_perm |= (RGW_PERM_WRITE | RGW_PERM_WRITE_ACP);
+ }
+ if (policy_perm & RGW_PERM_READ_OBJS) {
+ policy_perm |= (RGW_PERM_READ | RGW_PERM_READ_ACP);
+ }
+
+ uint32_t acl_perm = policy_perm & perm & user_perm_mask;
+
+ ldpp_dout(dpp, 10) << " identity=" << auth_identity
+ << " requested perm (type)=" << perm
+ << ", policy perm=" << policy_perm
+ << ", user_perm_mask=" << user_perm_mask
+ << ", acl perm=" << acl_perm << dendl;
+
+ return (perm == acl_perm);
+}
+
+
+bool RGWAccessControlPolicy::is_public(const DoutPrefixProvider *dpp) const
+{
+
+ static constexpr auto public_groups = {ACL_GROUP_ALL_USERS,
+ ACL_GROUP_AUTHENTICATED_USERS};
+ return std::any_of(public_groups.begin(), public_groups.end(),
+ [&, dpp](ACLGroupTypeEnum g) {
+ auto p = acl.get_group_perm(dpp, g, RGW_PERM_FULL_CONTROL);
+ return (p != RGW_PERM_NONE) && (p != RGW_PERM_INVALID);
+ }
+ );
+
+}
+
+void ACLPermission::generate_test_instances(list<ACLPermission*>& o)
+{
+ ACLPermission *p = new ACLPermission;
+ p->set_permissions(RGW_PERM_WRITE_ACP);
+ o.push_back(p);
+ o.push_back(new ACLPermission);
+}
+
+void ACLPermission::dump(Formatter *f) const
+{
+ f->dump_int("flags", flags);
+}
+
+void ACLGranteeType::dump(Formatter *f) const
+{
+ f->dump_unsigned("type", type);
+}
+
+void ACLGrant::dump(Formatter *f) const
+{
+ f->open_object_section("type");
+ type.dump(f);
+ f->close_section();
+
+ f->dump_string("id", id.to_str());
+ f->dump_string("email", email);
+
+ f->open_object_section("permission");
+ permission.dump(f);
+ f->close_section();
+
+ f->dump_string("name", name);
+ f->dump_int("group", (int)group);
+ f->dump_string("url_spec", url_spec);
+}
+
+void ACLGrant::generate_test_instances(list<ACLGrant*>& o)
+{
+ rgw_user id("rgw");
+ string name, email;
+ name = "Mr. RGW";
+ email = "r@gw";
+
+ ACLGrant *g1 = new ACLGrant;
+ g1->set_canon(id, name, RGW_PERM_READ);
+ g1->email = email;
+ o.push_back(g1);
+
+ ACLGrant *g2 = new ACLGrant;
+ g1->set_group(ACL_GROUP_AUTHENTICATED_USERS, RGW_PERM_WRITE);
+ o.push_back(g2);
+
+ o.push_back(new ACLGrant);
+}
+
+void ACLGranteeType::generate_test_instances(list<ACLGranteeType*>& o)
+{
+ ACLGranteeType *t = new ACLGranteeType;
+ t->set(ACL_TYPE_CANON_USER);
+ o.push_back(t);
+ o.push_back(new ACLGranteeType);
+}
+
+void RGWAccessControlList::generate_test_instances(list<RGWAccessControlList*>& o)
+{
+ RGWAccessControlList *acl = new RGWAccessControlList(NULL);
+
+ list<ACLGrant *> glist;
+ list<ACLGrant *>::iterator iter;
+
+ ACLGrant::generate_test_instances(glist);
+ for (iter = glist.begin(); iter != glist.end(); ++iter) {
+ ACLGrant *grant = *iter;
+ acl->add_grant(grant);
+
+ delete grant;
+ }
+ o.push_back(acl);
+ o.push_back(new RGWAccessControlList(NULL));
+}
+
+void ACLOwner::generate_test_instances(list<ACLOwner*>& o)
+{
+ ACLOwner *owner = new ACLOwner;
+ owner->id = "rgw";
+ owner->display_name = "Mr. RGW";
+ o.push_back(owner);
+ o.push_back(new ACLOwner);
+}
+
+void RGWAccessControlPolicy::generate_test_instances(list<RGWAccessControlPolicy*>& o)
+{
+ list<RGWAccessControlList *> acl_list;
+ list<RGWAccessControlList *>::iterator iter;
+ for (iter = acl_list.begin(); iter != acl_list.end(); ++iter) {
+ RGWAccessControlList::generate_test_instances(acl_list);
+ iter = acl_list.begin();
+
+ RGWAccessControlPolicy *p = new RGWAccessControlPolicy(NULL);
+ RGWAccessControlList *l = *iter;
+ p->acl = *l;
+
+ string name = "radosgw";
+ rgw_user id("rgw");
+ p->owner.set_name(name);
+ p->owner.set_id(id);
+
+ o.push_back(p);
+
+ delete l;
+ }
+
+ o.push_back(new RGWAccessControlPolicy(NULL));
+}
+
+void RGWAccessControlList::dump(Formatter *f) const
+{
+ map<string, int>::const_iterator acl_user_iter = acl_user_map.begin();
+ f->open_array_section("acl_user_map");
+ for (; acl_user_iter != acl_user_map.end(); ++acl_user_iter) {
+ f->open_object_section("entry");
+ f->dump_string("user", acl_user_iter->first);
+ f->dump_int("acl", acl_user_iter->second);
+ f->close_section();
+ }
+ f->close_section();
+
+ map<uint32_t, int>::const_iterator acl_group_iter = acl_group_map.begin();
+ f->open_array_section("acl_group_map");
+ for (; acl_group_iter != acl_group_map.end(); ++acl_group_iter) {
+ f->open_object_section("entry");
+ f->dump_unsigned("group", acl_group_iter->first);
+ f->dump_int("acl", acl_group_iter->second);
+ f->close_section();
+ }
+ f->close_section();
+
+ multimap<string, ACLGrant>::const_iterator giter = grant_map.begin();
+ f->open_array_section("grant_map");
+ for (; giter != grant_map.end(); ++giter) {
+ f->open_object_section("entry");
+ f->dump_string("id", giter->first);
+ f->open_object_section("grant");
+ giter->second.dump(f);
+ f->close_section();
+ f->close_section();
+ }
+ f->close_section();
+}
+
+void ACLOwner::dump(Formatter *f) const
+{
+ encode_json("id", id.to_str(), f);
+ encode_json("display_name", display_name, f);
+}
+
+void ACLOwner::decode_json(JSONObj *obj) {
+ string id_str;
+ JSONDecoder::decode_json("id", id_str, obj);
+ id.from_str(id_str);
+ JSONDecoder::decode_json("display_name", display_name, obj);
+}
+
+void RGWAccessControlPolicy::dump(Formatter *f) const
+{
+ encode_json("acl", acl, f);
+ encode_json("owner", owner, f);
+}
+
+ACLGroupTypeEnum ACLGrant::uri_to_group(string& uri)
+{
+ // this is required for backward compatibility
+ return ACLGrant_S3::uri_to_group(uri);
+}
+