]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw: s3: implement GetBucketPolicyStatus API
authorAbhishek Lekshmanan <abhishek@suse.com>
Wed, 29 Jan 2020 10:26:21 +0000 (11:26 +0100)
committerAbhishek Lekshmanan <abhishek@suse.com>
Mon, 3 Feb 2020 16:53:30 +0000 (17:53 +0100)
This API returns whether the Bucket Policies/ACLs are public. There are a couple
of caveats:
- AWS currently returns PolicyNotFound error in case a bucket policy doesn't
exist, though a non existant bucket policy would mean the default ACLs apply
where the bucket is private, so error return here seems like an error
- the API spec mentions TRUE and FALSE as the response IsPublic element value,
however in practice both boto/aws clients and AWS S3 return/expect a lowercase
response.

Signed-off-by: Abhishek Lekshmanan <abhishek@suse.com>
Conflicts:
src/rgw/rgw_rest_s3.h
merge conflict after zipper rework, dropped a spurious newline in rgw_rest_s3.h
after get_obj_op decl.
src/rgw/rgw_common.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h:
merge conflict after bucket replication merge, trivial conflicts

src/rgw/rgw_auth_s3.cc
src/rgw/rgw_common.cc
src/rgw/rgw_common.h
src/rgw/rgw_iam_policy.h
src/rgw/rgw_op.cc
src/rgw/rgw_op.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_rest_s3.h

index 93e46bc4621b21fc3b47f3cf22fa7d7a142d9fe7..9a40fd86dbbe853a8411ef96bbcd07d7cf1daa02 100644 (file)
@@ -33,6 +33,7 @@ static const auto signed_subresources = {
   "notification",
   "partNumber",
   "policy",
+  "policyStatus",
   "requestPayment",
   "response-cache-control",
   "response-content-disposition",
index d3c8434369099b9ab0f49387346392387c3debe7..93c625ab5997eb38752e2fd68a9c346206eb2a3f 100644 (file)
@@ -848,7 +848,8 @@ void RGWHTTPArgs::append(const string& name, const string& val)
       (name.compare("torrent") == 0) ||
       (name.compare("tagging") == 0) ||
       (name.compare("append") == 0) ||
-      (name.compare("position") == 0)) {
+      (name.compare("position") == 0) ||
+      (name.compare("policyStatus") == 0)) {
     sub_resources[name] = val;
   } else if (name[0] == 'r') { // root of all evil
     if ((name.compare("response-content-type") == 0) ||
index 739b26720af01ad7b92b7f8692fc60151ef4ce2e..30df2dcfcba10add8130fd07aec1951bfa0ca2a1 100644 (file)
@@ -534,6 +534,8 @@ enum RGWOpType {
   RGW_OP_GET_BUCKET_REPLICATION,
   RGW_OP_PUT_BUCKET_REPLICATION,
   RGW_OP_DELETE_BUCKET_REPLICATION,
+
+  RGW_OP_GET_BUCKET_POLICY_STATUS
 };
 
 class RGWAccessControlPolicy;
index dfe1a857cc9f12e69be66bd53316d24fa8b0274d..21f8ead8e7229b01baa9236a1b1f0c35903ff79d 100644 (file)
@@ -100,7 +100,8 @@ static constexpr std::uint64_t s3GetObjectRetention = 57;
 static constexpr std::uint64_t s3PutObjectLegalHold = 58;
 static constexpr std::uint64_t s3GetObjectLegalHold = 59;
 static constexpr std::uint64_t s3BypassGovernanceRetention = 60;
-static constexpr std::uint64_t s3All = 61;
+static constexpr std::uint64_t s3GetBucketPolicyStatus = 61;
+static constexpr std::uint64_t s3All = 62;
 
 static constexpr std::uint64_t iamPutUserPolicy = s3All + 1;
 static constexpr std::uint64_t iamGetUserPolicy = s3All + 2;
@@ -190,6 +191,7 @@ inline int op_to_perm(std::uint64_t op) {
   case s3GetBucketLogging:
   case s3GetBucketNotification:
   case s3GetBucketPolicy:
+  case s3GetBucketPolicyStatus:
   case s3GetBucketRequestPayment:
   case s3GetBucketTagging:
   case s3GetBucketVersioning:
index e02e1f9d96512810cf1cf6d8528dc36197100f97..c2f4a98d255361c786117747dbba4549ae8328f8 100644 (file)
@@ -8063,3 +8063,26 @@ void RGWGetClusterStat::execute()
 }
 
 
+int RGWGetBucketPolicyStatus::verify_permission()
+{
+  if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketPolicyStatus)) {
+    return -EACCES;
+  }
+
+  return 0;
+}
+
+void RGWGetBucketPolicyStatus::execute()
+{
+  static constexpr auto public_groups = {ACL_GROUP_ALL_USERS,
+                                        ACL_GROUP_AUTHENTICATED_USERS};
+
+  const auto& bucket_acl = s->bucket_acl->get_acl();
+  isPublic = std::any_of(public_groups.begin(), public_groups.end(),
+                        [&bucket_acl](ACLGroupTypeEnum g) {
+                           auto p = bucket_acl.get_group_perm(g, RGW_PERM_FULL_CONTROL);
+                           return (p != RGW_PERM_NONE) && (p != RGW_PERM_INVALID);
+                         }
+                        );
+  ldout(s->cct,20) << __func__ << "ACL public status=" << isPublic << dendl;
+}
index e6d90341c5fdb5d0c6b1b373daa1e885fb51b92a..131db7c91a80e2e8c4f64be9381d7fd4e2922795 100644 (file)
@@ -2384,6 +2384,18 @@ public:
   dmc::client_id dmclock_client() override { return dmc::client_id::admin; }
 };
 
+class RGWGetBucketPolicyStatus : public RGWOp {
+protected:
+  bool isPublic {false};
+public:
+  int verify_permission() override;
+  const char* name() const override { return "get_bucket_policy_status"; }
+  virtual RGWOpType get_type() override { return RGW_OP_GET_BUCKET_POLICY_STATUS; }
+  virtual uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
+  void execute() override;
+  dmc::client_id dmclock_client() override { return dmc::client_id::metadata; }
+};
+
 static inline int parse_value_and_bound(
     const string &input,
     int &output,
index 4867a252cfd6601a1dd98068564b9a4d1bbc2512..95df630396a27b51344d82ada264468298491a68 100644 (file)
@@ -4163,6 +4163,25 @@ void RGWGetObjLegalHold_ObjStore_S3::send_response()
   rgw_flush_formatter_and_reset(s, s->formatter);
 }
 
+void RGWGetBucketPolicyStatus_ObjStore_S3::send_response()
+{
+  if (op_ret) {
+    set_req_state_err(s, op_ret);
+  }
+  dump_errno(s);
+  end_header(s, this, "application/xml");
+  dump_start(s);
+
+  s->formatter->open_object_section_in_ns("PolicyStatus", XMLNS_AWS_S3);
+  // https://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETPolicyStatus.html
+  // mentions TRUE and FALSE, but boto/aws official clients seem to want lower
+  // case which is returned by AWS as well; so let's be bug to bug compatible
+  // with the API
+  s->formatter->dump_string("IsPublic", isPublic ? "true" : "false");
+  s->formatter->close_section();
+  rgw_flush_formatter_and_reset(s, s->formatter);
+
+}
 
 RGWOp *RGWHandler_REST_Service_S3::op_get()
 {
@@ -4283,6 +4302,8 @@ RGWOp *RGWHandler_REST_Bucket_S3::op_get()
     return RGWHandler_REST_PSNotifs_S3::create_get_op();
   } else if (is_replication_op()) {
     return new RGWGetBucketReplication_ObjStore_S3;
+  } else if (is_policy_status_op()) {
+    return new RGWGetBucketPolicyStatus_ObjStore_S3;
   }
   return get_obj_op(true);
 }
index 513be8a0ebc2a5d545870b2eeea314ecf5f52f46..b0e080b255028230ba757aa44be08d61c80d3a81 100644 (file)
@@ -570,6 +570,11 @@ public:
   void send_response() override;
 };
 
+class RGWGetBucketPolicyStatus_ObjStore_S3 : public RGWGetBucketPolicyStatus {
+public:
+  void send_response() override;
+};
+
 class RGW_Auth_S3 {
 public:
   static int authorize(const DoutPrefixProvider *dpp,
@@ -676,9 +681,11 @@ protected:
   bool is_replication_op() const {
     return s->info.args.exists("replication");
   }
+  bool is_policy_status_op() {
+    return s->info.args.exists("policyStatus");
+  }
 
   RGWOp *get_obj_op(bool get_data) const;
-
   RGWOp *op_get() override;
   RGWOp *op_head() override;
   RGWOp *op_put() override;