Skip to content

Commit e834454

Browse files
committed
rgw/s3: add Put/Get/DeleteBucketOwnershipControls
Signed-off-by: Casey Bodley <[email protected]>
1 parent 5ed9b1f commit e834454

File tree

9 files changed

+254
-0
lines changed

9 files changed

+254
-0
lines changed

src/rgw/rgw_common.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ rgw_http_errors rgw_http_s3_errors({
145145
{ EDQUOT, {507, "InsufficientCapacity"}},
146146
{ ENOSPC, {507, "InsufficientCapacity"}},
147147
{ ERR_ACLS_NOT_SUPPORTED, {400, "AccessControlListNotSupported"}},
148+
{ ERR_INVALID_BUCKET_ACL, {400, "InvalidBucketAclWithObjectOwnership"}},
149+
{ ERR_NO_SUCH_OWNERSHIP_CONTROLS, {404, "OwnershipControlsNotFoundError"}},
148150
});
149151

150152
rgw_http_errors rgw_http_swift_errors({

src/rgw/rgw_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ inline constexpr const char* RGW_REST_STS_XMLNS =
353353
#define ERR_AUTHORIZATION 2225 // SNS 403 AuthorizationError
354354
#define ERR_ILLEGAL_LOCATION_CONSTRAINT_EXCEPTION 2226
355355
#define ERR_ACLS_NOT_SUPPORTED 2227 // 400 AccessControlListNotSupported
356+
#define ERR_INVALID_BUCKET_ACL 2228 // 400 InvalidBucketAclWithObjectOwnership
357+
#define ERR_NO_SUCH_OWNERSHIP_CONTROLS 2229 // 404 OwnershipControlsNotFoundError
356358

357359
#define ERR_BUSY_RESHARDING 2300 // also in cls_rgw_types.h, don't change!
358360
#define ERR_NO_SUCH_ENTITY 2301

src/rgw/rgw_iam_policy.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ inline int op_to_perm(std::uint64_t op) {
303303
case s3GetReplicationConfiguration:
304304
case s3GetBucketObjectLockConfiguration:
305305
case s3GetBucketPublicAccessBlock:
306+
case s3GetBucketOwnershipControls:
306307
return RGW_PERM_READ_ACP;
307308

308309
case s3DeleteBucketPolicy:
@@ -326,6 +327,7 @@ inline int op_to_perm(std::uint64_t op) {
326327
case s3PutReplicationConfiguration:
327328
case s3PutBucketObjectLockConfiguration:
328329
case s3PutBucketPublicAccessBlock:
330+
case s3PutBucketOwnershipControls:
329331
return RGW_PERM_WRITE_ACP;
330332

331333
case s3All:

src/rgw/rgw_op.cc

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9570,6 +9570,119 @@ void RGWDeleteBucketEncryption::execute(optional_yield y)
95709570
}, y);
95719571
}
95729572

9573+
int RGWPutBucketOwnershipControls::verify_permission(optional_yield y)
9574+
{
9575+
if (!verify_bucket_permission(this, s, rgw::IAM::s3PutBucketOwnershipControls)) {
9576+
return -EACCES;
9577+
}
9578+
return 0;
9579+
}
9580+
9581+
void RGWPutBucketOwnershipControls::execute(optional_yield y)
9582+
{
9583+
op_ret = get_params(y);
9584+
if (op_ret < 0) {
9585+
return;
9586+
}
9587+
9588+
op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id,
9589+
&data, nullptr, s->info, s->err, y);
9590+
if (op_ret < 0) {
9591+
ldpp_dout(this, 20) << "forward_request_to_master returned ret=" << op_ret << dendl;
9592+
return;
9593+
}
9594+
9595+
bufferlist conf_bl;
9596+
encode(ownership, conf_bl);
9597+
9598+
// construct a default private acl for BucketOwnerEnforced comparison
9599+
RGWAccessControlPolicy private_acl;
9600+
private_acl.create_default(s->bucket_owner.id,
9601+
s->bucket_owner.display_name);
9602+
9603+
op_ret = retry_raced_bucket_write(this, s->bucket.get(),
9604+
[this, y, &conf_bl, &private_acl] {
9605+
rgw::sal::Attrs& attrs = s->bucket->get_attrs();
9606+
9607+
using rgw::s3::ObjectOwnership::BucketOwnerEnforced;
9608+
if (ownership.object_ownership == BucketOwnerEnforced) {
9609+
// reject BucketOwnerEnforced if the bucket's acl doesn't
9610+
// match the default private acl policy
9611+
RGWAccessControlPolicy bucket_acl;
9612+
if (auto i = attrs.find(RGW_ATTR_ACL); i != attrs.end()) {
9613+
try {
9614+
auto p = i->second.cbegin();
9615+
decode(bucket_acl, p);
9616+
} catch (const buffer::error&) {
9617+
ldpp_dout(this, 20) << "failed to decode RGW_ATTR_ACL" << dendl;
9618+
return -EIO;
9619+
}
9620+
if (bucket_acl != private_acl) {
9621+
s->err.message = "The bucket's ACL must be made private "
9622+
"before setting BucketOwnerEnforced.";
9623+
return -ERR_INVALID_BUCKET_ACL;
9624+
}
9625+
}
9626+
}
9627+
9628+
attrs[RGW_ATTR_OWNERSHIP_CONTROLS] = conf_bl;
9629+
return s->bucket->put_info(this, false, real_time(), y);
9630+
}, y);
9631+
}
9632+
9633+
int RGWGetBucketOwnershipControls::verify_permission(optional_yield y)
9634+
{
9635+
if (!verify_bucket_permission(this, s, rgw::IAM::s3GetBucketOwnershipControls)) {
9636+
return -EACCES;
9637+
}
9638+
return 0;
9639+
}
9640+
9641+
void RGWGetBucketOwnershipControls::execute(optional_yield y)
9642+
{
9643+
const auto& attrs = s->bucket_attrs;
9644+
if (auto aiter = attrs.find(RGW_ATTR_OWNERSHIP_CONTROLS);
9645+
aiter == attrs.end()) {
9646+
op_ret = -ENOENT;
9647+
s->err.message = "The bucket ownership controls were not found";
9648+
return;
9649+
} else {
9650+
bufferlist::const_iterator iter{&aiter->second};
9651+
try {
9652+
decode(ownership, iter);
9653+
} catch (const buffer::error& e) {
9654+
ldpp_dout(this, 0) << __func__ << " failed to decode "
9655+
"RGW_ATTR_OWNERSHIP_CONTROLS: " << e.what() << dendl;
9656+
op_ret = -EIO;
9657+
return;
9658+
}
9659+
}
9660+
}
9661+
9662+
int RGWDeleteBucketOwnershipControls::verify_permission(optional_yield y)
9663+
{
9664+
if (!verify_bucket_permission(this, s, rgw::IAM::s3PutBucketOwnershipControls)) {
9665+
return -EACCES;
9666+
}
9667+
return 0;
9668+
}
9669+
9670+
void RGWDeleteBucketOwnershipControls::execute(optional_yield y)
9671+
{
9672+
op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->owner.id,
9673+
nullptr, nullptr, s->info, s->err, y);
9674+
if (op_ret < 0) {
9675+
ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl;
9676+
return;
9677+
}
9678+
9679+
op_ret = retry_raced_bucket_write(this, s->bucket.get(), [this, y] {
9680+
rgw::sal::Attrs& attrs = s->bucket->get_attrs();
9681+
attrs.erase(RGW_ATTR_OWNERSHIP_CONTROLS);
9682+
return s->bucket->put_info(this, false, real_time(), y);
9683+
}, y);
9684+
}
9685+
95739686
void rgw_slo_entry::decode_json(JSONObj *obj)
95749687
{
95759688
JSONDecoder::decode_json("path", path, obj);

src/rgw/rgw_op.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,6 +1934,39 @@ class RGWDeleteBucketEncryption : public RGWOp {
19341934
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
19351935
};
19361936

1937+
class RGWPutBucketOwnershipControls : public RGWOp {
1938+
protected:
1939+
rgw::s3::OwnershipControls ownership;
1940+
bufferlist data;
1941+
public:
1942+
virtual int get_params(optional_yield y) = 0;
1943+
int verify_permission(optional_yield y) override;
1944+
void execute(optional_yield y) override;
1945+
const char* name() const override { return "put_bucket_ownership_controls"; }
1946+
RGWOpType get_type() override { return RGW_OP_PUT_BUCKET_OWNERSHIP_CONTROLS; }
1947+
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
1948+
};
1949+
1950+
class RGWGetBucketOwnershipControls : public RGWOp {
1951+
protected:
1952+
rgw::s3::OwnershipControls ownership;
1953+
public:
1954+
int verify_permission(optional_yield y) override;
1955+
void execute(optional_yield y) override;
1956+
const char* name() const override { return "get_bucket_ownership_controls"; }
1957+
RGWOpType get_type() override { return RGW_OP_GET_BUCKET_OWNERSHIP_CONTROLS; }
1958+
uint32_t op_mask() override { return RGW_OP_TYPE_READ; }
1959+
};
1960+
1961+
class RGWDeleteBucketOwnershipControls : public RGWOp {
1962+
public:
1963+
int verify_permission(optional_yield y) override;
1964+
void execute(optional_yield y) override;
1965+
const char* name() const override { return "delete_bucket_ownership_controls"; }
1966+
RGWOpType get_type() override { return RGW_OP_DELETE_BUCKET_OWNERSHIP_CONTROLS; }
1967+
uint32_t op_mask() override { return RGW_OP_TYPE_WRITE; }
1968+
};
1969+
19371970
class RGWGetRequestPayment : public RGWOp {
19381971
protected:
19391972
bool requester_pays;

src/rgw/rgw_op_type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ enum RGWOpType {
6969
RGW_OP_GET_OBJ_RETENTION,
7070
RGW_OP_PUT_OBJ_LEGAL_HOLD,
7171
RGW_OP_GET_OBJ_LEGAL_HOLD,
72+
RGW_OP_PUT_BUCKET_OWNERSHIP_CONTROLS,
73+
RGW_OP_GET_BUCKET_OWNERSHIP_CONTROLS,
74+
RGW_OP_DELETE_BUCKET_OWNERSHIP_CONTROLS,
7275
// IAM
7376
RGW_OP_PUT_USER_POLICY,
7477
RGW_OP_GET_USER_POLICY,

src/rgw/rgw_rest.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,12 @@ class RGWDeleteBucketEncryption_ObjStore : public RGWDeleteBucketEncryption {
434434
~RGWDeleteBucketEncryption_ObjStore() override {}
435435
};
436436

437+
class RGWGetBucketOwnershipControls_ObjStore : public RGWGetBucketOwnershipControls {};
438+
439+
class RGWPutBucketOwnershipControls_ObjStore : public RGWPutBucketOwnershipControls {};
440+
441+
class RGWDeleteBucketOwnershipControls_ObjStore : public RGWDeleteBucketOwnershipControls {};
442+
437443
class RGWInitMultipart_ObjStore : public RGWInitMultipart {
438444
public:
439445
RGWInitMultipart_ObjStore() {}

src/rgw/rgw_rest_s3.cc

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,6 +4408,73 @@ void RGWDeleteBucketEncryption_ObjStore_S3::send_response()
44084408
end_header(s);
44094409
}
44104410

4411+
int RGWPutBucketOwnershipControls_ObjStore_S3::get_params(optional_yield y)
4412+
{
4413+
const auto max_size = s->cct->_conf->rgw_max_put_param_size;
4414+
int ret = 0;
4415+
std::tie(ret, data) = read_all_input(s, max_size, false);
4416+
if (ret < 0) {
4417+
return ret;
4418+
}
4419+
4420+
RGWXMLParser parser;
4421+
if (!parser.init()) {
4422+
return -EINVAL;
4423+
}
4424+
if (!parser.parse(data.c_str(), data.length(), 1)) {
4425+
ldpp_dout(this, 5) << "ERROR: malformed XML" << dendl;
4426+
return -ERR_MALFORMED_XML;
4427+
}
4428+
XMLObj* o = parser.find_first("OwnershipControls");
4429+
if (!o) {
4430+
s->err.message = "Missing required element OwnershipControls";
4431+
return -ERR_MALFORMED_XML;
4432+
}
4433+
if (!ownership.decode_xml(o, s->err.message)) {
4434+
return -ERR_MALFORMED_XML;
4435+
}
4436+
return 0;
4437+
}
4438+
4439+
void RGWPutBucketOwnershipControls_ObjStore_S3::send_response()
4440+
{
4441+
if (op_ret) {
4442+
set_req_state_err(s, op_ret);
4443+
}
4444+
dump_errno(s);
4445+
end_header(s);
4446+
}
4447+
4448+
void RGWGetBucketOwnershipControls_ObjStore_S3::send_response()
4449+
{
4450+
if (op_ret) {
4451+
if (op_ret == -ENOENT)
4452+
set_req_state_err(s, -ERR_NO_SUCH_OWNERSHIP_CONTROLS);
4453+
else
4454+
set_req_state_err(s, op_ret);
4455+
}
4456+
4457+
dump_errno(s);
4458+
end_header(s, this, to_mime_type(s->format));
4459+
dump_start(s);
4460+
4461+
if (!op_ret) {
4462+
encode_xml("OwnershipControls", XMLNS_AWS_S3, ownership, s->formatter);
4463+
rgw_flush_formatter_and_reset(s, s->formatter);
4464+
}
4465+
}
4466+
4467+
void RGWDeleteBucketOwnershipControls_ObjStore_S3::send_response()
4468+
{
4469+
if (op_ret == 0) {
4470+
op_ret = STATUS_NO_CONTENT;
4471+
}
4472+
4473+
set_req_state_err(s, op_ret);
4474+
dump_errno(s);
4475+
end_header(s);
4476+
}
4477+
44114478
void RGWGetRequestPayment_ObjStore_S3::send_response()
44124479
{
44134480
dump_errno(s);
@@ -5235,6 +5302,8 @@ RGWOp *RGWHandler_REST_Bucket_S3::op_get()
52355302
return new RGWGetBucketPublicAccessBlock_ObjStore_S3;
52365303
} else if (is_bucket_encryption_op()) {
52375304
return new RGWGetBucketEncryption_ObjStore_S3;
5305+
} else if (is_bucket_ownership_op()) {
5306+
return new RGWGetBucketOwnershipControls_ObjStore_S3;
52385307
}
52395308
return get_obj_op(true);
52405309
}
@@ -5293,6 +5362,8 @@ RGWOp *RGWHandler_REST_Bucket_S3::op_put()
52935362
return new RGWPutBucketPublicAccessBlock_ObjStore_S3;
52945363
} else if (is_bucket_encryption_op()) {
52955364
return new RGWPutBucketEncryption_ObjStore_S3;
5365+
} else if (is_bucket_ownership_op()) {
5366+
return new RGWPutBucketOwnershipControls_ObjStore_S3;
52965367
}
52975368
return new RGWCreateBucket_ObjStore_S3;
52985369
}
@@ -5318,6 +5389,8 @@ RGWOp *RGWHandler_REST_Bucket_S3::op_delete()
53185389
return new RGWDeleteBucketPublicAccessBlock;
53195390
} else if (is_bucket_encryption_op()) {
53205391
return new RGWDeleteBucketEncryption_ObjStore_S3;
5392+
} else if (is_bucket_ownership_op()) {
5393+
return new RGWDeleteBucketOwnershipControls_ObjStore_S3;
53215394
}
53225395

53235396
if (s->info.args.sub_resource_exists("website")) {
@@ -6510,6 +6583,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
65106583
case RGW_OP_PUT_BUCKET_LOGGING:
65116584
case RGW_OP_POST_BUCKET_LOGGING:
65126585
case RGW_OP_GET_BUCKET_LOGGING:
6586+
case RGW_OP_PUT_BUCKET_OWNERSHIP_CONTROLS:
65136587
break;
65146588
default:
65156589
ldpp_dout(s, 10) << "ERROR: AWS4 completion for operation: " << s->op_type << ", NOT IMPLEMENTED" << dendl;

src/rgw/rgw_rest_s3.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,22 @@ class RGWDeleteBucketEncryption_ObjStore_S3 : public RGWDeleteBucketEncryption_O
467467
void send_response() override;
468468
};
469469

470+
class RGWGetBucketOwnershipControls_ObjStore_S3 : public RGWGetBucketOwnershipControls_ObjStore {
471+
public:
472+
void send_response() override;
473+
};
474+
475+
class RGWPutBucketOwnershipControls_ObjStore_S3 : public RGWPutBucketOwnershipControls_ObjStore {
476+
int get_params(optional_yield y) override;
477+
public:
478+
void send_response() override;
479+
};
480+
481+
class RGWDeleteBucketOwnershipControls_ObjStore_S3 : public RGWDeleteBucketOwnershipControls_ObjStore {
482+
public:
483+
void send_response() override;
484+
};
485+
470486
class RGWGetRequestPayment_ObjStore_S3 : public RGWGetRequestPayment {
471487
public:
472488
RGWGetRequestPayment_ObjStore_S3() {}
@@ -750,6 +766,9 @@ class RGWHandler_REST_Bucket_S3 : public RGWHandler_REST_S3 {
750766
bool is_bucket_encryption_op() {
751767
return s->info.args.exists("encryption");
752768
}
769+
bool is_bucket_ownership_op() const {
770+
return s->info.args.exists("ownershipControls");
771+
}
753772

754773
RGWOp *get_obj_op(bool get_data) const;
755774
RGWOp *op_get() override;

0 commit comments

Comments
 (0)