]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add basics for Swift Account ACLs.
authorRadoslaw Zarzynski <rzarzynski@mirantis.com>
Mon, 11 Jan 2016 17:49:21 +0000 (18:49 +0100)
committerRadoslaw Zarzynski <rzarzynski@mirantis.com>
Thu, 2 Jun 2016 13:30:39 +0000 (15:30 +0200)
Signed-off-by: Radoslaw Zarzynski <rzarzynski@mirantis.com>
src/rgw/rgw_acl_swift.cc
src/rgw/rgw_acl_swift.h
src/rgw/rgw_common.h
src/rgw/rgw_op.cc

index 83fdc09c0f5b2c4ed723feb9570eedb9fde6850e..de48b82a89129d643b9746a91972890d152c0cd1 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <list>
 
+#include "common/ceph_json.h"
 #include "rgw_common.h"
 #include "rgw_user.h"
 #include "rgw_acl_swift.h"
@@ -15,6 +16,9 @@ using namespace std;
 
 #define SWIFT_PERM_READ  RGW_PERM_READ_OBJS
 #define SWIFT_PERM_WRITE RGW_PERM_WRITE_OBJS
+/* FIXME: do we really need separate RW? */
+#define SWIFT_PERM_RWRT  (SWIFT_PERM_READ | SWIFT_PERM_WRITE)
+#define SWIFT_PERM_ADMIN RGW_PERM_FULL_CONTROL
 
 #define SWIFT_GROUP_ALL_USERS ".r:*"
 
@@ -136,3 +140,124 @@ void RGWAccessControlPolicy_SWIFT::to_str(string& read, string& write)
   }
 }
 
+void RGWAccessControlPolicy_SWIFTAcct::add_grants(RGWRados * const store,
+                                                  const list<string>& uids,
+                                                  const int perm)
+{
+  for (const auto uid : uids) {
+    ACLGrant grant;
+    RGWUserInfo grant_user;
+
+    if (uid_is_public(uid)) {
+      grant.set_group(ACL_GROUP_ALL_USERS, perm);
+      acl.add_grant(&grant);
+    } else  {
+      rgw_user user(uid);
+
+      if (rgw_get_user_info_by_uid(store, user, grant_user) < 0) {
+        ldout(cct, 10) << "grant user does not exist:" << uid << dendl;
+        /* skipping silently */
+      } else {
+        grant.set_canon(user, grant_user.display_name, perm);
+        acl.add_grant(&grant);
+      }
+    }
+  }
+}
+
+bool RGWAccessControlPolicy_SWIFTAcct::create(RGWRados * const store,
+                                              const rgw_user& id,
+                                              const std::string& name,
+                                              const std::string& acl_str)
+{
+  acl.create_default(id, name);
+  owner.set_id(id);
+  owner.set_name(name);
+
+  JSONParser parser;
+
+  if (!parser.parse(acl_str.c_str(), acl_str.length())) {
+    ldout(cct, 0) << "ERROR: JSONParser::parse returned error=" << dendl;
+    return false;
+  }
+
+  JSONObjIter iter = parser.find_first("admin");
+  if (!iter.end() && (*iter)->is_array()) {
+    list<string> admin;
+    decode_json_obj(admin, *iter);
+    ldout(cct, 0) << "admins: " << admin << dendl;
+
+    add_grants(store, admin, SWIFT_PERM_ADMIN);
+  }
+
+  iter = parser.find_first("read-write");
+  if (!iter.end() && (*iter)->is_array()) {
+    list<string> readwrite;
+    decode_json_obj(readwrite, *iter);
+    ldout(cct, 0) << "read-write: " << readwrite << dendl;
+
+    add_grants(store, readwrite, SWIFT_PERM_RWRT);
+  }
+
+  iter = parser.find_first("read-only");
+  if (!iter.end() && (*iter)->is_array()) {
+    list<string> readonly;
+    decode_json_obj(readonly, *iter);
+    ldout(cct, 0) << "read-only: " << readonly << dendl;
+
+    add_grants(store, readonly, SWIFT_PERM_READ);
+  }
+
+  return true;
+}
+
+void RGWAccessControlPolicy_SWIFTAcct::to_str(std::string& acl_str) const
+{
+  list<string> admin;
+  list<string> readwrite;
+  list<string> readonly;
+
+  /* Parition the grant map into three not-overlapping groups. */
+  for (const auto item : get_acl().get_grant_map()) {
+    const ACLGrant& grant = item.second;
+    const int perm = grant.get_permission().get_permissions();
+
+    rgw_user id;
+    if (!grant.get_id(id)) {
+      if (grant.get_group() != ACL_GROUP_ALL_USERS) {
+        continue;
+      }
+      id = SWIFT_GROUP_ALL_USERS;
+    }
+
+    if (SWIFT_PERM_ADMIN == (perm & SWIFT_PERM_ADMIN)) {
+      admin.insert(admin.end(), id.to_str());
+    } else if (SWIFT_PERM_RWRT == (perm & SWIFT_PERM_RWRT)) {
+      readwrite.insert(readwrite.end(), id.to_str());
+    } else if (SWIFT_PERM_READ == (perm & SWIFT_PERM_READ)) {
+      readonly.insert(readonly.end(), id.to_str());
+    } else {
+      // FIXME: print a warning
+    }
+  }
+
+  /* Serialize the groups. */
+  JSONFormatter formatter;
+
+  formatter.open_object_section("acl");
+  if (!readonly.empty()) {
+    encode_json("read-only", readonly, &formatter);
+  }
+  if (!readwrite.empty()) {
+    encode_json("read-write", readwrite, &formatter);
+  }
+  if (!admin.empty()) {
+    encode_json("admin", admin, &formatter);
+  }
+  formatter.close_section();
+
+  std::ostringstream oss;
+  formatter.flush(oss);
+
+  acl_str = oss.str();
+}
index ba72d7b914dc818a28a497ab3804b02d2c89f3c8..f791a2c2f3f041653ac577dc52080aef399d1b2e 100644 (file)
@@ -24,4 +24,19 @@ public:
   void to_str(string& read, string& write);
 };
 
+class RGWAccessControlPolicy_SWIFTAcct : public RGWAccessControlPolicy
+{
+public:
+  RGWAccessControlPolicy_SWIFTAcct(CephContext * const _cct)
+    : RGWAccessControlPolicy(_cct)
+  {}
+  ~RGWAccessControlPolicy_SWIFTAcct() {}
+
+  void add_grants(RGWRados *store, const list<string>& uids, int perm);
+  bool create(RGWRados *store,
+              const rgw_user& id,
+              const string& name,
+              const string& acl_str);
+  void to_str(string& acl) const;
+};
 #endif
index ce4ed52d1d1b5fdfba038a1f2e3e55178047ed90..4e9b7744183729ab08fdd4013c1310a240579913 100644 (file)
@@ -1279,6 +1279,7 @@ struct req_state {
    * through a well-defined interface. For more details, see rgw_auth.h. */
   std::unique_ptr<RGWIdentityApplier> auth_identity;
 
+  std::unique_ptr<RGWAccessControlPolicy> user_acl;
   RGWAccessControlPolicy *bucket_acl;
   RGWAccessControlPolicy *object_acl;
 
index 7a02047f1d7d0af5b8fb2aad557d79d1934e75c0..eff1684fae6e00fb1d1cd30ed23fe5d50c06b81d 100644 (file)
@@ -142,9 +142,32 @@ static int decode_policy(CephContext *cct, bufferlist& bl, RGWAccessControlPolic
   return 0;
 }
 
-static int get_bucket_policy_from_attr(CephContext *cct, RGWRados *store, void *ctx,
-                                       RGWBucketInfo& bucket_info, map<string, bufferlist>& bucket_attrs,
-                                       RGWAccessControlPolicy *policy, rgw_obj& obj)
+
+static int get_user_policy_from_attr(CephContext * const cct,
+                                     RGWRados * const store,
+                                     map<string, bufferlist>& attrs,
+                                     RGWAccessControlPolicy& policy    /* out */)
+{
+  auto aiter = attrs.find(RGW_ATTR_ACL);
+  if (aiter != attrs.end()) {
+    int ret = decode_policy(cct, aiter->second, &policy);
+    if (ret < 0) {
+      return ret;
+    }
+  } else {
+    return -ENOENT;
+  }
+
+  return 0;
+}
+
+static int get_bucket_policy_from_attr(CephContext *cct,
+                                       RGWRados *store,
+                                       void *ctx,
+                                       RGWBucketInfo& bucket_info,
+                                       map<string, bufferlist>& bucket_attrs,
+                                       RGWAccessControlPolicy *policy,
+                                       rgw_obj& obj)
 {
   map<string, bufferlist>::iterator aiter = bucket_attrs.find(RGW_ATTR_ACL);
 
@@ -294,9 +317,9 @@ static int read_policy(RGWRados *store, struct req_state *s,
 }
 
 /**
- * Get the AccessControlPolicy for a bucket or object off of disk.
+ * Get the AccessControlPolicy for an user, bucket or object off of disk.
  * s: The req_state to draw information from.
- * only_bucket: If true, reads the bucket ACL rather than the object ACL.
+ * only_bucket: If true, reads the user and bucket ACLs rather than the object ACL.
  * Returns: 0 on success, -ERR# otherwise.
  */
 int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
@@ -317,6 +340,8 @@ int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
   if(s->dialect.compare("s3") == 0) {
     s->bucket_acl = new RGWAccessControlPolicy_S3(s->cct);
   } else if(s->dialect.compare("swift")  == 0) {
+    s->user_acl = std::unique_ptr<RGWAccessControlPolicy>(
+        new RGWAccessControlPolicy_SWIFTAcct(s->cct));
     s->bucket_acl = new RGWAccessControlPolicy_SWIFT(s->cct);
   } else {
     s->bucket_acl = new RGWAccessControlPolicy(s->cct);
@@ -337,6 +362,14 @@ int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
     }
   }
 
+  struct {
+    rgw_user uid;
+    std::string display_name;
+  } acct_acl_user = {
+    s->user->user_id,
+    s->user->display_name,
+  };
+
   if (!s->bucket_name.empty()) {
     s->bucket_exists = true;
     if (s->bucket_instance_id.empty()) {
@@ -358,6 +391,10 @@ int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
     if (s->bucket_exists) {
       rgw_obj_key no_obj;
       ret = read_policy(store, s, s->bucket_info, s->bucket_attrs, s->bucket_acl, s->bucket, no_obj);
+      acct_acl_user = {
+        s->bucket_info.owner,
+        s->bucket_acl->get_owner().get_display_name(),
+      };
     } else {
       s->bucket_acl->create_default(s->user->user_id, s->user->display_name);
       ret = -ERR_NO_SUCH_BUCKET;
@@ -392,6 +429,36 @@ int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
     }
   }
 
+  /* handle user ACL only for those APIs which support it */
+  if (s->user_acl) {
+    map<string, bufferlist> uattrs;
+
+    ret = rgw_get_user_attrs_by_uid(store, acct_acl_user.uid, uattrs);
+    if (!ret) {
+      ret = get_user_policy_from_attr(s->cct, store, uattrs, *s->user_acl);
+    }
+    if (-ENOENT == ret) {
+      /* In already existing clusters users won't have ACL. In such case
+       * assuming that only account owner has the rights seems to be
+       * reasonable. That allows to have only one verification logic.
+       * NOTE: there is small compatibility kludge for global, empty tenant:
+       *  1. if we try to reach an existing bucket, its owner is considered
+       *     as account owner.
+       *  2. otherwise account owner is identity stored in s->user->user_id.  */
+      s->user_acl->create_default(acct_acl_user.uid,
+                                  acct_acl_user.display_name);
+      ret = 0;
+    } else {
+      ldout(s->cct, 0) << "NOTICE: couldn't get user attrs for handling ACL (user_id="
+                       << s->user->user_id
+                       << ", ret="
+                       << ret
+                       << ")" << dendl;
+      return ret;
+    }
+  }
+
+
   return ret;
 }