rgw: s3: implement GetBucketPolicyStatus API

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
This commit is contained in:
Abhishek Lekshmanan 2020-01-29 11:26:21 +01:00
parent 57baa84044
commit e0b4562c61
8 changed files with 72 additions and 3 deletions

View File

@ -33,6 +33,7 @@ static const auto signed_subresources = {
"notification",
"partNumber",
"policy",
"policyStatus",
"requestPayment",
"response-cache-control",
"response-content-disposition",

View 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) ||

View 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;

View 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:

View 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;
}

View 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,

View 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);
}

View 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;