]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
Set object ACLS to reflect bucket owner supporting bucket unlink/link.
authorShilpa Jagannath <smanjara@redhat.com>
Tue, 9 Apr 2019 10:08:25 +0000 (15:38 +0530)
committerShilpa Jagannath <smanjara@redhat.com>
Tue, 30 Jul 2019 08:30:45 +0000 (14:00 +0530)
Provides command line tool to update the acl on object
of a bucket after bucket unlink/link.
"radosgw-admin bucket chown --bucket <bucket>"

Signed-off-by: Shilpa Jagannath <smanjara@redhat.com>
src/rgw/rgw_acl.cc
src/rgw/rgw_acl.h
src/rgw/rgw_admin.cc
src/rgw/rgw_bucket.cc
src/rgw/rgw_bucket.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/test/cli/radosgw-admin/help.t

index 8c02f8e350e6451b46d1339e1a1f5cde4453dd4b..b2adbe6b61c45329feb54a8dcf974534792a034b 100644 (file)
@@ -52,6 +52,20 @@ void RGWAccessControlList::add_grant(ACLGrant *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)
index 0e84d75eef8c709fcd9cc138aedcf45a990d8456..dc8f25dd22457c7511bb8d111931dcad46d1ea36 100644 (file)
@@ -344,6 +344,7 @@ public:
   static void generate_test_instances(list<RGWAccessControlList*>& o);
 
   void add_grant(ACLGrant *grant);
+  void remove_canon_user_grant(rgw_user& user_id);
 
   multimap<string, ACLGrant>& get_grant_map() { return grant_map; }
   const multimap<string, ACLGrant>& get_grant_map() const { return grant_map; }
index 384b3549e9f540f1e0deec97f48f37ae32e37ecf..6a2ad126bfb1b975f18ece7f11fea31deb9217a2 100644 (file)
@@ -105,6 +105,7 @@ void usage()
   cout << "  bucket stats               returns bucket statistics\n";
   cout << "  bucket rm                  remove bucket\n";
   cout << "  bucket check               check bucket index\n";
+  cout << "  bucket chown               link bucket to specified user and update its object ACLs\n";
   cout << "  bucket reshard             reshard bucket\n";
   cout << "  bucket rewrite             rewrite all objects in the specified bucket\n";
   cout << "  bucket sync disable        disable bucket sync\n";
@@ -415,6 +416,7 @@ enum {
   OPT_BUCKET_RM,
   OPT_BUCKET_REWRITE,
   OPT_BUCKET_RESHARD,
+  OPT_BUCKET_CHOWN,
   OPT_POLICY,
   OPT_POOL_ADD,
   OPT_POOL_RM,
@@ -680,6 +682,8 @@ static int get_cmd(const char *cmd, const char *prev_cmd, const char *prev_prev_
       return OPT_BUCKET_STATS;
     if (strcmp(cmd, "rm") == 0)
       return OPT_BUCKET_RM;
+    if (strcmp(cmd, "chown") == 0)
+      return OPT_BUCKET_CHOWN;
     if (strcmp(cmd, "rewrite") == 0)
       return OPT_BUCKET_REWRITE;
     if (strcmp(cmd, "reshard") == 0)
@@ -5551,6 +5555,20 @@ int main(int argc, const char **argv)
     }
   }
 
+  if (opt_cmd == OPT_BUCKET_CHOWN) {
+
+    bucket_op.set_bucket_name(bucket_name);
+    bucket_op.set_new_bucket_name(new_bucket_name);
+    string err;
+    string marker;
+
+    int r = RGWBucketAdminOp::chown(store, bucket_op, marker, &err);
+    if (r < 0) {
+      cerr << "failure: " << cpp_strerror(-r) << ": " << err << std::endl;
+      return -r;
+    }
+  }
+
   if (opt_cmd == OPT_LOG_LIST) {
     // filter by date?
     if (date.size() && date.size() != 10) {
index 2a19b1b39dc511f5ab997ee2c51d4c92362ceda8..e1792ad30d07d636feb9ef4c6d0aeb8a5de869dc 100644 (file)
@@ -24,6 +24,7 @@
 #include "rgw_user.h"
 #include "rgw_string.h"
 #include "rgw_multi.h"
+#include "rgw_op.h"
 
 #include "services/svc_zone.h"
 #include "services/svc_sys_obj.h"
@@ -993,6 +994,113 @@ int RGWBucket::link(RGWBucketAdminOpState& op_state,
   return 0;
 }
 
+int RGWBucket::chown(RGWBucketAdminOpState& op_state,
+       map<string, bufferlist>& attrs, const string& marker, std::string *err_msg)
+{
+
+  //after bucket link
+  rgw_bucket& bucket = op_state.get_bucket();
+  tenant = bucket.tenant;
+  bucket_name = bucket.name;
+
+  std::vector<rgw_bucket_dir_entry> objs;
+  map<string, bool> common_prefixes;
+  RGWObjectCtx obj_ctx(store);
+
+  RGWBucketInfo bucket_info;
+  RGWSysObjectCtx sys_ctx = store->svc.sysobj->init_obj_ctx();
+
+  int ret = store->get_bucket_info(sys_ctx, tenant, bucket_name, bucket_info, NULL, &attrs);
+  if (ret < 0) {
+    set_err_msg(err_msg, "bucket info failed: tenant: " + tenant + "bucket_name: " + bucket_name + " " + cpp_strerror(-ret));
+    return ret;
+  }
+
+  RGWUserInfo user_info;
+  ret = rgw_get_user_info_by_uid(store, bucket_info.owner, user_info);
+  if (ret < 0) {
+    set_err_msg(err_msg, "user info failed: " + cpp_strerror(-ret));
+    return ret;
+  }
+
+  RGWRados::Bucket target(store, bucket_info);
+  RGWRados::Bucket::List list_op(&target);
+
+  list_op.params.list_versions = true;
+  list_op.params.allow_unordered = true;
+  list_op.params.marker = marker;
+
+  bool is_truncated = false;
+  int count = 0;
+  int max_entries = 1000;
+
+  //Loop through objects and update object acls to point to bucket owner
+
+  do {
+      objs.clear();
+      ret = list_op.list_objects(max_entries, &objs, &common_prefixes, &is_truncated);
+      if (ret < 0) {
+        set_err_msg(err_msg, "list objects failed: " + cpp_strerror(-ret));
+        return ret;
+      }
+
+      list_op.params.marker = list_op.get_next_marker();
+      count += objs.size();
+
+      for (const auto& obj : objs) {
+
+        const rgw_obj r_obj(bucket_info.bucket, obj.key);
+        ret = get_obj_attrs(store, obj_ctx, bucket_info, r_obj, attrs);
+        if (ret < 0){
+          set_err_msg(err_msg, "failed to read object " + obj.key.name +  "with " + cpp_strerror(-ret));
+          continue;
+        }
+        const auto& aiter = attrs.find(RGW_ATTR_ACL);
+        if (aiter == attrs.end()) {
+          set_err_msg(err_msg, "no acls found for object " + obj.key.name + " .Continuing with next object." + cpp_strerror(-ret));
+          continue;
+        } else {
+          bufferlist& bl = aiter->second;
+          RGWAccessControlPolicy policy(store->ctx());
+          ACLOwner owner;
+          try {
+            decode(policy, bl);
+            owner = policy.get_owner();
+          } catch (buffer::error& err) {
+            set_err_msg(err_msg, "decode policy failed: ");
+            return -EIO;
+          }
+
+          //Get the ACL from the policy
+          RGWAccessControlList& acl = policy.get_acl();
+
+          //Remove grant that is set to old owner
+          acl.remove_canon_user_grant(owner.get_id());
+
+          //Create a grant and add grant
+          ACLGrant grant;
+          grant.set_canon(bucket_info.owner, user_info.display_name, RGW_PERM_FULL_CONTROL);
+          acl.add_grant(&grant);
+
+          //Update the ACL owner to the new user
+          owner.set_id(bucket_info.owner);
+          owner.set_name(user_info.display_name);
+          policy.set_owner(owner);
+
+          bl.clear();
+          encode(policy, bl);
+
+          ret = modify_obj_attr(store, obj_ctx, bucket_info, r_obj, RGW_ATTR_ACL, bl);
+          if (ret < 0) {
+            set_err_msg(err_msg, "modify attr failed: " + cpp_strerror(-ret));
+            return ret;
+          }
+        }
+      } cerr << count << " objects processed, next marker " << list_op.params.marker.name << std::endl;
+    } while(is_truncated);
+    return 0;
+}
+
 int RGWBucket::unlink(RGWBucketAdminOpState& op_state, std::string *err_msg)
 {
   rgw_bucket bucket = op_state.get_bucket();
@@ -1433,6 +1541,23 @@ int RGWBucketAdminOp::link(RGWRados *store, RGWBucketAdminOpState& op_state, str
 
 }
 
+int RGWBucketAdminOp::chown(RGWRados *store, RGWBucketAdminOpState& op_state, const string& marker, string *err)
+{
+  RGWBucket bucket;
+  map<string, bufferlist> attrs;
+
+  int ret = bucket.init(store, op_state, err, &attrs);
+  if (ret < 0)
+    return ret;
+
+  ret = bucket.link(op_state, attrs, err);
+  if (ret < 0)
+    return ret;
+
+  return bucket.chown(op_state, attrs, marker, err);
+
+}
+
 int RGWBucketAdminOp::check_index(RGWRados *store, RGWBucketAdminOpState& op_state,
                   RGWFormatterFlusher& flusher, optional_yield y)
 {
index 166f2e4a0619e80dd3f9334d63db34a1f1ce0ef4..202eee0e903cbd38b1245a511921664b0c672fa3 100644 (file)
@@ -343,6 +343,7 @@ public:
   int remove(RGWBucketAdminOpState& op_state, optional_yield y, bool bypass_gc = false, bool keep_index_consistent = true, std::string *err_msg = NULL);
   int link(RGWBucketAdminOpState& op_state, map<string, bufferlist>& attrs,
        std::string *err_msg = NULL);
+  int chown(RGWBucketAdminOpState& op_state,  map<string, bufferlist>& attrs, const string& marker, std::string *err_msg = NULL);
   int unlink(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
   int set_quota(RGWBucketAdminOpState& op_state, std::string *err_msg = NULL);
 
@@ -367,6 +368,7 @@ public:
 
   static int unlink(RGWRados *store, RGWBucketAdminOpState& op_state);
   static int link(RGWRados *store, RGWBucketAdminOpState& op_state, string *err_msg = NULL);
+  static int chown(RGWRados *store, RGWBucketAdminOpState& op_state, const string& marker, string *err_msg = NULL);
 
   static int check_index(RGWRados *store, RGWBucketAdminOpState& op_state,
                   RGWFormatterFlusher& flusher, optional_yield y);
index 11c810aa8926d0af5f4ea68c94f7bb8004d9c7ba..0f2d53a265e232cd9c886a2e4cd729e17d06b4bd 100644 (file)
@@ -321,9 +321,9 @@ vector<Policy> get_iam_user_policy_from_attr(CephContext* cct,
   return policies;
 }
 
-static int get_obj_attrs(RGWRados *store, struct req_state *s, const rgw_obj& obj, map<string, bufferlist>& attrs)
+int get_obj_attrs(RGWRados *store, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& obj, map<string, bufferlist>& attrs)
 {
-  RGWRados::Object op_target(store, s->bucket_info, *static_cast<RGWObjectCtx *>(s->obj_ctx), obj);
+  RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
   RGWRados::Object::Read read_op(&op_target);
 
   read_op.params.attrs = &attrs;
@@ -440,14 +440,14 @@ static int get_multipart_info(RGWRados *store, struct req_state *s,
   return get_multipart_info(store, s, meta_obj, policy, attrs, upload_info);
 }
 
-static int modify_obj_attr(RGWRados *store, struct req_state *s, const rgw_obj& obj, const char* attr_name, bufferlist& attr_val)
+int modify_obj_attr(RGWRados *store, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& obj, const char* attr_name, bufferlist& attr_val)
 {
   map<string, bufferlist> attrs;
-  RGWRados::Object op_target(store, s->bucket_info, *static_cast<RGWObjectCtx *>(s->obj_ctx), obj);
+  RGWRados::Object op_target(store, bucket_info, obj_ctx, obj);
   RGWRados::Object::Read read_op(&op_target);
 
   read_op.params.attrs = &attrs;
-  
+
   int r = read_op.prepare(s->yield);
   if (r < 0) {
     return r;
@@ -813,7 +813,7 @@ static int rgw_iam_add_tags_from_bl(struct req_state* s, bufferlist& bl){
 static int rgw_iam_add_existing_objtags(RGWRados* store, struct req_state* s, rgw_obj& obj, std::uint64_t action){
   map <string, bufferlist> attrs;
   store->set_atomic(s->obj_ctx, obj);
-  int op_ret = get_obj_attrs(store, s, obj, attrs);
+  int op_ret = get_obj_attrs(store, *(s->obj_ctx), s->bucket_info, obj, attrs);
   if (op_ret < 0)
     return op_ret;
   auto tags = attrs.find(RGW_ATTR_TAGS);
@@ -1045,7 +1045,7 @@ void RGWGetObjTags::execute()
 
   store->set_atomic(s->obj_ctx, obj);
 
-  op_ret = get_obj_attrs(store, s, obj, attrs);
+  op_ret = get_obj_attrs(store, *(s->obj_ctx), s->bucket_info, obj, attrs);
   if (op_ret < 0) {
     ldpp_dout(this, 0) << "ERROR: failed to get obj attrs, obj=" << obj
         << " ret=" << op_ret << dendl;
@@ -1097,7 +1097,7 @@ void RGWPutObjTags::execute()
   rgw_obj obj;
   obj = rgw_obj(s->bucket, s->object);
   store->set_atomic(s->obj_ctx, obj);
-  op_ret = modify_obj_attr(store, s, obj, RGW_ATTR_TAGS, tags_bl);
+  op_ret = modify_obj_attr(store, *(s->obj_ctx), s->bucket_info, obj, RGW_ATTR_TAGS, tags_bl);
   if (op_ret == -ECANCELED){
     op_ret = -ERR_TAG_CONFLICT;
   }
@@ -4532,7 +4532,7 @@ void RGWPutMetadataObject::execute()
   }
 
   /* check if obj exists, read orig attrs */
-  op_ret = get_obj_attrs(store, s, obj, orig_attrs);
+  op_ret = get_obj_attrs(store, *(s->obj_ctx), s->bucket_info, obj, orig_attrs);
   if (op_ret < 0) {
     return;
   }
@@ -4689,7 +4689,7 @@ void RGWDeleteObj::execute()
   if (!s->object.empty()) {
     if (need_object_expiration() || multipart_delete) {
       /* check if obj exists, read orig attrs */
-      op_ret = get_obj_attrs(store, s, obj, attrs);
+      op_ret = get_obj_attrs(store, *(s->obj_ctx), s->bucket_info, obj, attrs);
       if (op_ret < 0) {
         return;
       }
@@ -5355,7 +5355,7 @@ void RGWPutACLs::execute()
     obj = rgw_obj(s->bucket, s->object);
     store->set_atomic(s->obj_ctx, obj);
     //if instance is empty, we should modify the latest object
-    op_ret = modify_obj_attr(store, s, obj, RGW_ATTR_ACL, bl);
+    op_ret = modify_obj_attr(store, *(s->obj_ctx), s->bucket_info, obj, RGW_ATTR_ACL, bl);
   } else {
     attrs = s->bucket_attrs;
     attrs[RGW_ATTR_ACL] = bl;
@@ -5916,7 +5916,7 @@ void RGWCompleteMultipart::execute()
     return;
   }
 
-  op_ret = get_obj_attrs(store, s, meta_obj, attrs);
+  op_ret = get_obj_attrs(store, *(s->obj_ctx), s->bucket_info, meta_obj, attrs);
 
   if (op_ret < 0) {
     ldpp_dout(this, 0) << "ERROR: failed to get obj attrs, obj=" << meta_obj
index ecbedde64adbeec4b5006627b8a8f572486736ae..d7128111b878d8bb40ab8c2aebaf41a15131f4ce 100644 (file)
@@ -2380,5 +2380,7 @@ static inline int parse_value_and_bound(
   return 0;
 }
 
+int get_obj_attrs(RGWRados *store, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& obj, map<string, bufferlist>& attrs);
+int modify_obj_attr(RGWRados *store, RGWObjectCtx& obj_ctx, RGWBucketInfo& bucket_info, const rgw_obj& obj, const char* attr_name, bufferlist& attr_val);
 
 #endif /* CEPH_RGW_OP_H */
index cb8f46ca468438908b0bc0003f6073544d1b6ce5..a24f94497f9a19d9efefe2215224df5f70a2b0cd 100644 (file)
@@ -25,6 +25,7 @@
     bucket stats               returns bucket statistics
     bucket rm                  remove bucket
     bucket check               check bucket index
+    bucket chown               link bucket to specified user and update its object ACLs
     bucket reshard             reshard bucket
     bucket rewrite             rewrite all objects in the specified bucket
     bucket sync disable        disable bucket sync