feat: adds the x-amz-expected-bucket-owner check in the gateway

Fixes #1428

The `x-amz-expected-bucket-owner` header in S3 specifies the account ID of the expected bucket owner. If the account ID provided does not match the actual owner of the bucket, the request fails with an HTTP 403 Forbidden (AccessDenied) error. If the provided account ID is not 12 characters long, S3 returns a 400 Bad Request error.

In our case, we expect the header to contain the bucket owner’s access key ID, and we skip validation errors related to the access key ID, since there is no validation mechanism for user access key IDs. If the provided value does not match the bucket owner’s access key ID, the gateway returns an AccessDenied error.

A few integration tests are added for random actions, as this feature applies to all actions, but it is unnecessary to add test cases for every single one.
This commit is contained in:
niksis02
2025-10-15 19:20:04 +04:00
parent af550c8f80
commit d39685947d
3 changed files with 119 additions and 0 deletions

View File

@@ -101,6 +101,7 @@ func TestDeleteBucket(ts *TestState) {
ts.Run(DeleteBucket_non_existing_bucket)
ts.Run(DeleteBucket_non_empty_bucket)
ts.Run(DeleteBucket_success_status_code)
ts.Run(DeleteBucket_incorrect_expected_bucket_owner)
}
func TestPutBucketOwnershipControls(ts *TestState) {
@@ -291,6 +292,8 @@ func TestDeleteObject(ts *TestState) {
ts.Run(DeleteObject_conditional_writes)
ts.Run(DeleteObject_success)
ts.Run(DeleteObject_success_status_code)
ts.Run(DeleteObject_incorrect_expected_bucket_owner)
ts.Run(DeleteObject_expected_bucket_owner)
}
func TestDeleteObjects(ts *TestState) {
@@ -348,6 +351,7 @@ func TestDeleteObjectTagging(ts *TestState) {
ts.Run(DeleteObjectTagging_non_existing_object)
ts.Run(DeleteObjectTagging_success_status)
ts.Run(DeleteObjectTagging_success)
ts.Run(DeleteObjectTagging_expected_bucket_owner)
}
func TestCreateMultipartUpload(ts *TestState) {
@@ -1128,6 +1132,7 @@ func GetIntTests() IntTests {
"ListBuckets_success": ListBuckets_success,
"DeleteBucket_non_existing_bucket": DeleteBucket_non_existing_bucket,
"DeleteBucket_non_empty_bucket": DeleteBucket_non_empty_bucket,
"DeleteBucket_incorrect_expected_bucket_owner": DeleteBucket_incorrect_expected_bucket_owner,
"DeleteBucket_success_status_code": DeleteBucket_success_status_code,
"PutBucketOwnershipControls_non_existing_bucket": PutBucketOwnershipControls_non_existing_bucket,
"PutBucketOwnershipControls_multiple_rules": PutBucketOwnershipControls_multiple_rules,
@@ -1238,6 +1243,8 @@ func GetIntTests() IntTests {
"DeleteObject_directory_object": DeleteObject_directory_object,
"DeleteObject_success": DeleteObject_success,
"DeleteObject_success_status_code": DeleteObject_success_status_code,
"DeleteObject_incorrect_expected_bucket_owner": DeleteObject_incorrect_expected_bucket_owner,
"DeleteObject_expected_bucket_owner": DeleteObject_expected_bucket_owner,
"DeleteObjects_empty_input": DeleteObjects_empty_input,
"DeleteObjects_non_existing_objects": DeleteObjects_non_existing_objects,
"DeleteObjects_success": DeleteObjects_success,
@@ -1277,6 +1284,7 @@ func GetIntTests() IntTests {
"DeleteObjectTagging_non_existing_object": DeleteObjectTagging_non_existing_object,
"DeleteObjectTagging_success_status": DeleteObjectTagging_success_status,
"DeleteObjectTagging_success": DeleteObjectTagging_success,
"DeleteObjectTagging_expected_bucket_owner": DeleteObjectTagging_expected_bucket_owner,
"CreateMultipartUpload_non_existing_bucket": CreateMultipartUpload_non_existing_bucket,
"CreateMultipartUpload_with_metadata": CreateMultipartUpload_with_metadata,
"CreateMultipartUpload_with_tagging": CreateMultipartUpload_with_tagging,