summaryrefslogtreecommitdiffstats
path: root/src/rgw/rgw_acl.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/rgw/rgw_acl.h')
-rw-r--r--src/rgw/rgw_acl.h469
1 files changed, 469 insertions, 0 deletions
diff --git a/src/rgw/rgw_acl.h b/src/rgw/rgw_acl.h
new file mode 100644
index 00000000..0e84d75e
--- /dev/null
+++ b/src/rgw/rgw_acl.h
@@ -0,0 +1,469 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_RGW_ACL_H
+#define CEPH_RGW_ACL_H
+
+#include <map>
+#include <string>
+#include <include/types.h>
+
+#include <boost/optional.hpp>
+#include <boost/utility/string_ref.hpp>
+
+#include "common/debug.h"
+
+#include "rgw_basic_types.h"
+
+#define RGW_PERM_NONE 0x00
+#define RGW_PERM_READ 0x01
+#define RGW_PERM_WRITE 0x02
+#define RGW_PERM_READ_ACP 0x04
+#define RGW_PERM_WRITE_ACP 0x08
+#define RGW_PERM_READ_OBJS 0x10
+#define RGW_PERM_WRITE_OBJS 0x20
+#define RGW_PERM_FULL_CONTROL ( RGW_PERM_READ | RGW_PERM_WRITE | \
+ RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP )
+#define RGW_PERM_ALL_S3 RGW_PERM_FULL_CONTROL
+#define RGW_PERM_INVALID 0xFF00
+
+static constexpr char RGW_REFERER_WILDCARD[] = "*";
+
+enum ACLGranteeTypeEnum {
+/* numbers are encoded, should not change */
+ ACL_TYPE_CANON_USER = 0,
+ ACL_TYPE_EMAIL_USER = 1,
+ ACL_TYPE_GROUP = 2,
+ ACL_TYPE_UNKNOWN = 3,
+ ACL_TYPE_REFERER = 4,
+};
+
+enum ACLGroupTypeEnum {
+/* numbers are encoded should not change */
+ ACL_GROUP_NONE = 0,
+ ACL_GROUP_ALL_USERS = 1,
+ ACL_GROUP_AUTHENTICATED_USERS = 2,
+};
+
+class ACLPermission
+{
+protected:
+ int flags;
+public:
+ ACLPermission() : flags(0) {}
+ ~ACLPermission() {}
+ uint32_t get_permissions() const { return flags; }
+ void set_permissions(uint32_t perm) { flags = perm; }
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(2, 2, bl);
+ encode(flags, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
+ decode(flags, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ static void generate_test_instances(list<ACLPermission*>& o);
+};
+WRITE_CLASS_ENCODER(ACLPermission)
+
+class ACLGranteeType
+{
+protected:
+ __u32 type;
+public:
+ ACLGranteeType() : type(ACL_TYPE_UNKNOWN) {}
+ virtual ~ACLGranteeType() {}
+// virtual const char *to_string() = 0;
+ ACLGranteeTypeEnum get_type() const { return (ACLGranteeTypeEnum)type; }
+ void set(ACLGranteeTypeEnum t) { type = t; }
+// virtual void set(const char *s) = 0;
+ void encode(bufferlist& bl) const {
+ ENCODE_START(2, 2, bl);
+ encode(type, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
+ decode(type, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ static void generate_test_instances(list<ACLGranteeType*>& o);
+};
+WRITE_CLASS_ENCODER(ACLGranteeType)
+
+class ACLGrantee
+{
+public:
+ ACLGrantee() {}
+ ~ACLGrantee() {}
+};
+
+
+class ACLGrant
+{
+protected:
+ ACLGranteeType type;
+ rgw_user id;
+ string email;
+ ACLPermission permission;
+ string name;
+ ACLGroupTypeEnum group;
+ string url_spec;
+
+public:
+ ACLGrant() : group(ACL_GROUP_NONE) {}
+ virtual ~ACLGrant() {}
+
+ /* there's an assumption here that email/uri/id encodings are
+ different and there can't be any overlap */
+ bool get_id(rgw_user& _id) const {
+ switch(type.get_type()) {
+ case ACL_TYPE_EMAIL_USER:
+ _id = email; // implies from_str() that parses the 't:u' syntax
+ return true;
+ case ACL_TYPE_GROUP:
+ case ACL_TYPE_REFERER:
+ return false;
+ default:
+ _id = id;
+ return true;
+ }
+ }
+ ACLGranteeType& get_type() { return type; }
+ const ACLGranteeType& get_type() const { return type; }
+ ACLPermission& get_permission() { return permission; }
+ const ACLPermission& get_permission() const { return permission; }
+ ACLGroupTypeEnum get_group() const { return group; }
+ const string& get_referer() const { return url_spec; }
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(5, 3, bl);
+ encode(type, bl);
+ string s;
+ id.to_str(s);
+ encode(s, bl);
+ string uri;
+ encode(uri, bl);
+ encode(email, bl);
+ encode(permission, bl);
+ encode(name, bl);
+ __u32 g = (__u32)group;
+ encode(g, bl);
+ encode(url_spec, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl);
+ decode(type, bl);
+ string s;
+ decode(s, bl);
+ id.from_str(s);
+ string uri;
+ decode(uri, bl);
+ decode(email, bl);
+ decode(permission, bl);
+ decode(name, bl);
+ if (struct_v > 1) {
+ __u32 g;
+ decode(g, bl);
+ group = (ACLGroupTypeEnum)g;
+ } else {
+ group = uri_to_group(uri);
+ }
+ if (struct_v >= 5) {
+ decode(url_spec, bl);
+ } else {
+ url_spec.clear();
+ }
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ static void generate_test_instances(list<ACLGrant*>& o);
+
+ ACLGroupTypeEnum uri_to_group(string& uri);
+
+ void set_canon(const rgw_user& _id, const string& _name, const uint32_t perm) {
+ type.set(ACL_TYPE_CANON_USER);
+ id = _id;
+ name = _name;
+ permission.set_permissions(perm);
+ }
+ void set_group(ACLGroupTypeEnum _group, const uint32_t perm) {
+ type.set(ACL_TYPE_GROUP);
+ group = _group;
+ permission.set_permissions(perm);
+ }
+ void set_referer(const std::string& _url_spec, const uint32_t perm) {
+ type.set(ACL_TYPE_REFERER);
+ url_spec = _url_spec;
+ permission.set_permissions(perm);
+ }
+};
+WRITE_CLASS_ENCODER(ACLGrant)
+
+struct ACLReferer {
+ std::string url_spec;
+ uint32_t perm;
+
+ ACLReferer() : perm(0) {}
+ ACLReferer(const std::string& url_spec,
+ const uint32_t perm)
+ : url_spec(url_spec),
+ perm(perm) {
+ }
+
+ bool is_match(boost::string_ref http_referer) const {
+ const auto http_host = get_http_host(http_referer);
+ if (!http_host || http_host->length() < url_spec.length()) {
+ return false;
+ }
+
+ if ("*" == url_spec) {
+ return true;
+ }
+
+ if (http_host->compare(url_spec) == 0) {
+ return true;
+ }
+
+ if ('.' == url_spec[0]) {
+ /* Wildcard support: a referer matches the spec when its last char are
+ * perfectly equal to spec. */
+ return http_host->ends_with(url_spec);
+ }
+
+ return false;
+ }
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(url_spec, bl);
+ encode(perm, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl);
+ decode(url_spec, bl);
+ decode(perm, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+
+private:
+ boost::optional<boost::string_ref> get_http_host(const boost::string_ref url) const {
+ size_t pos = url.find("://");
+ if (pos == boost::string_ref::npos || url.starts_with("://") ||
+ url.ends_with("://") || url.ends_with('@')) {
+ return boost::none;
+ }
+ boost::string_ref url_sub = url.substr(pos + strlen("://"));
+ pos = url_sub.find('@');
+ if (pos != boost::string_ref::npos) {
+ url_sub = url_sub.substr(pos + 1);
+ }
+ pos = url_sub.find_first_of("/:");
+ if (pos == boost::string_ref::npos) {
+ /* no port or path exists */
+ return url_sub;
+ }
+ return url_sub.substr(0, pos);
+ }
+};
+WRITE_CLASS_ENCODER(ACLReferer)
+
+namespace rgw {
+namespace auth {
+ class Identity;
+}
+}
+
+class RGWAccessControlList
+{
+protected:
+ CephContext *cct;
+ /* FIXME: in the feature we should consider switching to uint32_t also
+ * in data structures. */
+ map<string, int> acl_user_map;
+ map<uint32_t, int> acl_group_map;
+ list<ACLReferer> referer_list;
+ multimap<string, ACLGrant> grant_map;
+ void _add_grant(ACLGrant *grant);
+public:
+ explicit RGWAccessControlList(CephContext *_cct) : cct(_cct) {}
+ RGWAccessControlList() : cct(NULL) {}
+
+ void set_ctx(CephContext *ctx) {
+ cct = ctx;
+ }
+
+ virtual ~RGWAccessControlList() {}
+
+ uint32_t get_perm(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ uint32_t perm_mask);
+ uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
+ uint32_t get_referer_perm(uint32_t current_perm,
+ std::string http_referer,
+ uint32_t perm_mask);
+ void encode(bufferlist& bl) const {
+ ENCODE_START(4, 3, bl);
+ bool maps_initialized = true;
+ encode(maps_initialized, bl);
+ encode(acl_user_map, bl);
+ encode(grant_map, bl);
+ encode(acl_group_map, bl);
+ encode(referer_list, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
+ bool maps_initialized;
+ decode(maps_initialized, bl);
+ decode(acl_user_map, bl);
+ decode(grant_map, bl);
+ if (struct_v >= 2) {
+ decode(acl_group_map, bl);
+ } else if (!maps_initialized) {
+ multimap<string, ACLGrant>::iterator iter;
+ for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
+ ACLGrant& grant = iter->second;
+ _add_grant(&grant);
+ }
+ }
+ if (struct_v >= 4) {
+ decode(referer_list, bl);
+ }
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ static void generate_test_instances(list<RGWAccessControlList*>& o);
+
+ void add_grant(ACLGrant *grant);
+
+ multimap<string, ACLGrant>& get_grant_map() { return grant_map; }
+ const multimap<string, ACLGrant>& get_grant_map() const { return grant_map; }
+
+ void create_default(const rgw_user& id, string name) {
+ acl_user_map.clear();
+ acl_group_map.clear();
+ referer_list.clear();
+
+ ACLGrant grant;
+ grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
+ add_grant(&grant);
+ }
+};
+WRITE_CLASS_ENCODER(RGWAccessControlList)
+
+class ACLOwner
+{
+protected:
+ rgw_user id;
+ string display_name;
+public:
+ ACLOwner() {}
+ ~ACLOwner() {}
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(3, 2, bl);
+ string s;
+ id.to_str(s);
+ encode(s, bl);
+ encode(display_name, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
+ string s;
+ decode(s, bl);
+ id.from_str(s);
+ decode(display_name, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ void decode_json(JSONObj *obj);
+ static void generate_test_instances(list<ACLOwner*>& o);
+ void set_id(const rgw_user& _id) { id = _id; }
+ void set_name(const string& name) { display_name = name; }
+
+ rgw_user& get_id() { return id; }
+ const rgw_user& get_id() const { return id; }
+ string& get_display_name() { return display_name; }
+};
+WRITE_CLASS_ENCODER(ACLOwner)
+
+class RGWAccessControlPolicy
+{
+protected:
+ CephContext *cct;
+ RGWAccessControlList acl;
+ ACLOwner owner;
+
+public:
+ explicit RGWAccessControlPolicy(CephContext *_cct) : cct(_cct), acl(_cct) {}
+ RGWAccessControlPolicy() : cct(NULL), acl(NULL) {}
+ virtual ~RGWAccessControlPolicy() {}
+
+ void set_ctx(CephContext *ctx) {
+ cct = ctx;
+ acl.set_ctx(ctx);
+ }
+
+ uint32_t get_perm(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ uint32_t perm_mask,
+ const char * http_referer);
+ uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
+ bool verify_permission(const DoutPrefixProvider* dpp,
+ const rgw::auth::Identity& auth_identity,
+ uint32_t user_perm_mask,
+ uint32_t perm,
+ const char * http_referer = nullptr);
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(2, 2, bl);
+ encode(owner, bl);
+ encode(acl, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::const_iterator& bl) {
+ DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
+ decode(owner, bl);
+ decode(acl, bl);
+ DECODE_FINISH(bl);
+ }
+ void dump(Formatter *f) const;
+ static void generate_test_instances(list<RGWAccessControlPolicy*>& o);
+ void decode_owner(bufferlist::const_iterator& bl) { // sometimes we only need that, should be faster
+ DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
+ decode(owner, bl);
+ DECODE_FINISH(bl);
+ }
+
+ void set_owner(ACLOwner& o) { owner = o; }
+ ACLOwner& get_owner() {
+ return owner;
+ }
+
+ void create_default(const rgw_user& id, string& name) {
+ acl.create_default(id, name);
+ owner.set_id(id);
+ owner.set_name(name);
+ }
+ RGWAccessControlList& get_acl() {
+ return acl;
+ }
+ const RGWAccessControlList& get_acl() const {
+ return acl;
+ }
+
+ virtual bool compare_group_name(string& id, ACLGroupTypeEnum group) { return false; }
+};
+WRITE_CLASS_ENCODER(RGWAccessControlPolicy)
+
+#endif