tags = new ArrayList<>();
+ tags.add(Tag.builder().key("env").value("test").build());
+ tags.add(Tag.builder().key("project").value("example").build());
+ PutObjectTaggingRequest wrongRequest = PutObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .tagging(Tagging.builder().tagSet(tags).build())
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.putObjectTagging(wrongRequest));
+
+ PutObjectTaggingRequest correctRequest = PutObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .tagging(Tagging.builder().tagSet(tags).build())
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.putObjectTagging(correctRequest));
+ }
+
+ @Test
+ public void testCreateMultipartKey() {
+ CreateMultipartUploadRequest wrongRequest = CreateMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.createMultipartUpload(wrongRequest));
+
+ CreateMultipartUploadRequest correctRequest = CreateMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.createMultipartUpload(correctRequest));
+ }
+
+ @Test
+ public void testCreateMultipartByCopy() {
+ String sourceKey = "test-multipart-by-copy-source-key";
+ String destKey = "test-multipart-by-copy-dest-key";
+
+ s3Client.putObject(b -> b.bucket(DEFAULT_BUCKET_NAME).key(sourceKey), fromString(TEST_CONTENT));
+
+ CreateMultipartUploadResponse initResponse =
+ s3Client.createMultipartUpload(b -> b.bucket(DEFAULT_BUCKET_NAME).key(destKey));
+
+ String uploadId = initResponse.uploadId();
+
+ UploadPartCopyRequest wrongRequest = UploadPartCopyRequest.builder()
+ .sourceBucket(DEFAULT_BUCKET_NAME)
+ .sourceKey(sourceKey)
+ .expectedSourceBucketOwner(WRONG_OWNER)
+ .destinationBucket(DEFAULT_BUCKET_NAME)
+ .destinationKey(destKey)
+ .uploadId(uploadId)
+ .partNumber(1)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.uploadPartCopy(wrongRequest));
+
+ UploadPartCopyRequest correctRequest = UploadPartCopyRequest.builder()
+ .sourceBucket(DEFAULT_BUCKET_NAME)
+ .sourceKey(sourceKey)
+ .expectedSourceBucketOwner(correctOwner)
+ .destinationBucket(DEFAULT_BUCKET_NAME)
+ .destinationKey(destKey)
+ .uploadId(uploadId)
+ .expectedBucketOwner(correctOwner)
+ .partNumber(1)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.uploadPartCopy(correctRequest));
+ }
+
+ @Test
+ public void testCopyObject() {
+ String sourceKey = "test-copy-object-source-key";
+ String destKey = "test-copy-object-dest-key";
+ s3Client.putObject(b -> b.bucket(DEFAULT_BUCKET_NAME).key(sourceKey), fromString("test"));
+
+ CopyObjectRequest wrongRequest = CopyObjectRequest.builder()
+ .sourceBucket(DEFAULT_BUCKET_NAME)
+ .sourceKey(sourceKey)
+ .destinationBucket(DEFAULT_BUCKET_NAME)
+ .destinationKey(destKey)
+ .expectedSourceBucketOwner(WRONG_OWNER)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.copyObject(wrongRequest));
+
+ CopyObjectRequest correctRequest = CopyObjectRequest.builder()
+ .sourceBucket(DEFAULT_BUCKET_NAME)
+ .sourceKey(sourceKey)
+ .destinationBucket(DEFAULT_BUCKET_NAME)
+ .destinationKey(destKey)
+ .expectedSourceBucketOwner(correctOwner)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.copyObject(correctRequest));
+ }
+
+ @Test
+ public void testCreateDirectory() {
+ String newKey = "create-directory-key/";
+
+ PutObjectRequest wrongRequest = PutObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.putObject(wrongRequest, RequestBody.empty()));
+
+ PutObjectRequest correctRequest = PutObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.putObject(correctRequest, RequestBody.empty()));
+ }
+
+ @Test
+ public void testGetKey() {
+ GetObjectRequest correctRequest = GetObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.getObject(correctRequest));
+
+ GetObjectRequest wrongRequest = GetObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.getObject(wrongRequest));
+ }
+
+ @Test
+ public void testGetObjectTagging() {
+ GetObjectTaggingRequest correctRequest = GetObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.getObjectTagging(correctRequest));
+
+ GetObjectTaggingRequest wrongRequest = GetObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.getObjectTagging(wrongRequest));
+ }
+
+ @Test
+ public void testListParts() {
+ String newKey = "list-parts-key";
+ CreateMultipartUploadResponse multipartUploadResponse = s3Client.createMultipartUpload(b -> {
+ b.bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .build();
+ });
+
+ String uploadId = multipartUploadResponse.uploadId();
+
+ s3Client.uploadPart(
+ UploadPartRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .partNumber(1)
+ .contentLength((long) TEST_CONTENT.getBytes(StandardCharsets.UTF_8).length)
+ .build(), fromString(TEST_CONTENT));
+
+ ListPartsRequest correctRequest = ListPartsRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.listParts(correctRequest));
+
+ ListPartsRequest wrongResponse = ListPartsRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.listParts(wrongResponse));
+ }
+
+ @Test
+ public void testHeadKey() {
+ HeadObjectRequest correctRequest = HeadObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.headObject(correctRequest));
+
+ HeadObjectRequest wrongRequest = HeadObjectRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ S3Exception exception = assertThrows(S3Exception.class, () -> s3Client.headObject(wrongRequest));
+ assertEquals(403, exception.statusCode());
+ }
+
+ @Test
+ public void testDeleteKey() {
+ String newKey = "delete-key";
+ s3Client.putObject(b -> b.bucket(DEFAULT_BUCKET_NAME).key(newKey), fromString(TEST_CONTENT));
+
+ DeleteObjectsRequest wrongRequest = DeleteObjectsRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .expectedBucketOwner(WRONG_OWNER)
+ .delete(Delete.builder().objects(ObjectIdentifier.builder().key(newKey).build()).build())
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.deleteObjects(wrongRequest));
+
+ DeleteObjectsRequest correctRequest = DeleteObjectsRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .expectedBucketOwner(correctOwner)
+ .delete(Delete.builder().objects(ObjectIdentifier.builder().key(newKey).build()).build())
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.deleteObjects(correctRequest));
+ }
+
+ @Test
+ public void testDeleteObjectTagging() {
+ DeleteObjectTaggingRequest correctRequest = DeleteObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.deleteObjectTagging(correctRequest));
+
+ DeleteObjectTaggingRequest wrongRequest = DeleteObjectTaggingRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.deleteObjectTagging(wrongRequest));
+ }
+
+ @Test
+ public void testAbortMultipartUpload() {
+ CreateMultipartUploadResponse multipartUploadResponse =
+ s3Client.createMultipartUpload(b -> b.bucket(DEFAULT_BUCKET_NAME).key(BUCKET_VERIFICATION_TEST_KEY));
+
+ String uploadId = multipartUploadResponse.uploadId();
+
+ AbortMultipartUploadRequest wrongRequest = AbortMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .uploadId(uploadId)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.abortMultipartUpload(wrongRequest));
+
+ AbortMultipartUploadRequest correctRequest = AbortMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(BUCKET_VERIFICATION_TEST_KEY)
+ .uploadId(uploadId)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.abortMultipartUpload(correctRequest));
+ }
+
+ @Test
+ public void testInitMultipartUpload() {
+ String newKey = "init-multipart-upload-key";
+
+ CreateMultipartUploadRequest wrongRequest = CreateMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.createMultipartUpload(wrongRequest));
+
+ CreateMultipartUploadRequest correctRequest = CreateMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.createMultipartUpload(correctRequest));
+ }
+
+ @Test
+ public void testCompleteMultipartUpload() {
+ String newKey = "complete-multipart-upload-key";
+ CreateMultipartUploadResponse multipartUploadResponse =
+ s3Client.createMultipartUpload(b -> b.bucket(DEFAULT_BUCKET_NAME).key(newKey));
+
+ String uploadId = multipartUploadResponse.uploadId();
+
+ UploadPartResponse uploadPartResponse = s3Client.uploadPart(b -> b.bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .partNumber(1)
+ .contentLength((long) TEST_CONTENT.getBytes(StandardCharsets.UTF_8).length)
+ .build(), fromString(TEST_CONTENT));
+
+ CompletedMultipartUpload completedUpload = CompletedMultipartUpload.builder()
+ .parts(
+ CompletedPart.builder().partNumber(1).eTag(uploadPartResponse.eTag()).build()
+ ).build();
+
+
+ CompleteMultipartUploadRequest wrongRequest = CompleteMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .multipartUpload(completedUpload)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.completeMultipartUpload(wrongRequest));
+
+ CompleteMultipartUploadRequest correctRequest = CompleteMultipartUploadRequest.builder()
+ .bucket(DEFAULT_BUCKET_NAME)
+ .key(newKey)
+ .uploadId(uploadId)
+ .multipartUpload(completedUpload)
+ .expectedBucketOwner(correctOwner)
+ .build();
+ verifyPassBucketOwnershipVerification(() -> s3Client.completeMultipartUpload(correctRequest));
+ }
+ }
+
+ @Nested
+ @TestInstance(TestInstance.Lifecycle.PER_CLASS)
+ class LinkBucketTests {
+ private static final String NON_S3_VOLUME_NAME = "link-bucket-volume";
+ private OzoneVolume nonS3Volume;
+ private OzoneVolume s3Volume;
+
+ @BeforeAll
+ public void setup() throws Exception {
+ try (OzoneClient ozoneClient = cluster.newClient()) {
+ ozoneClient.getObjectStore().createVolume(NON_S3_VOLUME_NAME);
+ nonS3Volume = ozoneClient.getObjectStore().getVolume(NON_S3_VOLUME_NAME);
+ s3Volume = ozoneClient.getObjectStore().getS3Volume();
+ }
+ }
+
+ @Test
+ public void setBucketVerificationOnLinkBucket() throws Exception {
+ // create link bucket
+ String linkBucketName = "link-bucket";
+ nonS3Volume.createBucket(OzoneConsts.BUCKET);
+ BucketArgs.Builder bb = new BucketArgs.Builder()
+ .setStorageType(StorageType.DEFAULT)
+ .setVersioning(false)
+ .setSourceVolume(NON_S3_VOLUME_NAME)
+ .setSourceBucket(OzoneConsts.BUCKET);
+ s3Volume.createBucket(linkBucketName, bb.build());
+
+ GetBucketAclRequest wrongRequest = GetBucketAclRequest.builder()
+ .bucket(linkBucketName)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.getBucketAcl(wrongRequest));
+
+ String owner = s3Client.getBucketAcl(GetBucketAclRequest.builder()
+ .bucket(linkBucketName)
+ .build()).owner().displayName();
+ GetBucketAclRequest correctRequest = GetBucketAclRequest.builder()
+ .bucket(linkBucketName)
+ .expectedBucketOwner(owner)
+ .build();
+
+ verifyPassBucketOwnershipVerification(() -> s3Client.getBucketAcl(correctRequest));
+ }
+
+ @Test
+ public void testDanglingBucket() throws Exception {
+ String sourceBucket = "source-bucket";
+ String linkBucket = "link-bucket-dangling";
+ nonS3Volume.createBucket(sourceBucket);
+ BucketArgs.Builder bb = new BucketArgs.Builder()
+ .setStorageType(StorageType.DEFAULT)
+ .setVersioning(false)
+ .setSourceVolume(NON_S3_VOLUME_NAME)
+ .setSourceBucket(sourceBucket);
+ s3Volume.createBucket(linkBucket, bb.build());
+
+ // remove source bucket to make dangling bucket
+ nonS3Volume.deleteBucket(sourceBucket);
+
+ GetBucketAclRequest wrongRequest = GetBucketAclRequest.builder()
+ .bucket(linkBucket)
+ .expectedBucketOwner(WRONG_OWNER)
+ .build();
+
+ verifyBucketOwnershipVerificationAccessDenied(() -> s3Client.getBucketAcl(wrongRequest));
+
+ String owner = s3Client.getBucketAcl(GetBucketAclRequest.builder()
+ .bucket(linkBucket)
+ .build()).owner().displayName();
+ GetBucketAclRequest correctRequest = GetBucketAclRequest.builder()
+ .bucket(linkBucket)
+ .expectedBucketOwner(owner)
+ .build();
+
+ verifyPassBucketOwnershipVerification(() -> s3Client.getBucketAcl(correctRequest));
+ }
+ }
+
+ private void verifyPassBucketOwnershipVerification(Executable function) {
+ assertDoesNotThrow(function);
+ }
+
+ private void verifyBucketOwnershipVerificationAccessDenied(Executable function) {
+ S3Exception exception = assertThrows(S3Exception.class, function);
+ assertEquals(403, exception.statusCode());
+ assertEquals("Access Denied", exception.awsErrorDetails().errorCode());
+ }
+ }
}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
index cb641d1ea016..cd3739c4023d 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpoint.java
@@ -93,6 +93,9 @@ public class BucketEndpoint extends EndpointBase {
private static final Logger LOG =
LoggerFactory.getLogger(BucketEndpoint.class);
+ @Context
+ private HttpHeaders headers;
+
private boolean listKeysShallowEnabled;
private int maxKeysLimit = 1000;
@@ -120,8 +123,7 @@ public Response get(
@QueryParam("acl") String aclMarker,
@QueryParam("key-marker") String keyMarker,
@QueryParam("upload-id-marker") String uploadIdMarker,
- @DefaultValue("1000") @QueryParam("max-uploads") int maxUploads,
- @Context HttpHeaders hh) throws OS3Exception, IOException {
+ @DefaultValue("1000") @QueryParam("max-uploads") int maxUploads) throws OS3Exception, IOException {
long startNanos = Time.monotonicNowNanos();
S3GAction s3GAction = S3GAction.GET_BUCKET;
PerformanceStringBuilder perf = new PerformanceStringBuilder();
@@ -132,6 +134,8 @@ public Response get(
OzoneBucket bucket = null;
try {
+ bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
if (aclMarker != null) {
s3GAction = S3GAction.GET_ACL;
S3BucketAcl result = getAcl(bucketName);
@@ -167,7 +171,6 @@ public Response get(
boolean shallow = listKeysShallowEnabled
&& OZONE_URI_DELIMITER.equals(delimiter);
- bucket = getBucket(bucketName);
ozoneKeyIterator = bucket.listKeys(prefix, prevKey, shallow);
} catch (OMException ex) {
@@ -309,7 +312,6 @@ private int validateMaxKeys(int maxKeys) throws OS3Exception {
@PUT
public Response put(@PathParam("bucket") String bucketName,
@QueryParam("acl") String aclMarker,
- @Context HttpHeaders httpHeaders,
InputStream body) throws IOException, OS3Exception {
long startNanos = Time.monotonicNowNanos();
S3GAction s3GAction = S3GAction.CREATE_BUCKET;
@@ -317,7 +319,7 @@ public Response put(@PathParam("bucket") String bucketName,
try {
if (aclMarker != null) {
s3GAction = S3GAction.PUT_ACL;
- Response response = putAcl(bucketName, httpHeaders, body);
+ Response response = putAcl(bucketName, body);
AUDIT.logWriteSuccess(
buildAuditMessageForSuccess(s3GAction, getAuditParameters()));
return response;
@@ -413,7 +415,8 @@ public Response head(@PathParam("bucket") String bucketName)
long startNanos = Time.monotonicNowNanos();
S3GAction s3GAction = S3GAction.HEAD_BUCKET;
try {
- getBucket(bucketName);
+ OzoneBucket bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
AUDIT.logReadSuccess(
buildAuditMessageForSuccess(s3GAction, getAuditParameters()));
getMetrics().updateHeadBucketSuccessStats(startNanos);
@@ -438,6 +441,8 @@ public Response delete(@PathParam("bucket") String bucketName)
S3GAction s3GAction = S3GAction.DELETE_BUCKET;
try {
+ OzoneBucket bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
deleteS3Bucket(bucketName);
} catch (OMException ex) {
AUDIT.logWriteFailure(
@@ -492,6 +497,7 @@ public MultiDeleteResponse multiDelete(@PathParam("bucket") String bucketName,
}
long startNanos = Time.monotonicNowNanos();
try {
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
undeletedKeyResultMap = bucket.deleteKeys(deleteKeys, true);
for (DeleteObject d : request.getObjects()) {
ErrorInfo error = undeletedKeyResultMap.get(d.getKey());
@@ -540,10 +546,7 @@ public S3BucketAcl getAcl(String bucketName)
S3BucketAcl result = new S3BucketAcl();
try {
OzoneBucket bucket = getBucket(bucketName);
- OzoneVolume volume = getVolume();
- // TODO: use bucket owner instead of volume owner here once bucket owner
- // TODO: is supported.
- S3Owner owner = S3Owner.of(volume.getOwner());
+ S3Owner owner = S3Owner.of(bucket.getOwner());
result.setOwner(owner);
// TODO: remove this duplication avoid logic when ACCESS and DEFAULT scope
@@ -581,17 +584,18 @@ public S3BucketAcl getAcl(String bucketName)
*
* see: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html
*/
- public Response putAcl(String bucketName, HttpHeaders httpHeaders,
+ public Response putAcl(String bucketName,
InputStream body) throws IOException, OS3Exception {
long startNanos = Time.monotonicNowNanos();
- String grantReads = httpHeaders.getHeaderString(S3Acl.GRANT_READ);
- String grantWrites = httpHeaders.getHeaderString(S3Acl.GRANT_WRITE);
- String grantReadACP = httpHeaders.getHeaderString(S3Acl.GRANT_READ_CAP);
- String grantWriteACP = httpHeaders.getHeaderString(S3Acl.GRANT_WRITE_CAP);
- String grantFull = httpHeaders.getHeaderString(S3Acl.GRANT_FULL_CONTROL);
+ String grantReads = headers.getHeaderString(S3Acl.GRANT_READ);
+ String grantWrites = headers.getHeaderString(S3Acl.GRANT_WRITE);
+ String grantReadACP = headers.getHeaderString(S3Acl.GRANT_READ_CAP);
+ String grantWriteACP = headers.getHeaderString(S3Acl.GRANT_WRITE_CAP);
+ String grantFull = headers.getHeaderString(S3Acl.GRANT_FULL_CONTROL);
try {
OzoneBucket bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
OzoneVolume volume = getVolume();
List ozoneAclListOnBucket = new ArrayList<>();
@@ -770,6 +774,11 @@ public OzoneConfiguration getOzoneConfiguration() {
return this.ozoneConfiguration;
}
+ @VisibleForTesting
+ public void setHeaders(HttpHeaders headers) {
+ this.headers = headers;
+ }
+
@Override
@PostConstruct
public void init() {
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
index 7ebed80c2878..02482023e5df 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/ObjectEndpoint.java
@@ -243,6 +243,9 @@ public Response put(
throw newError(NOT_IMPLEMENTED, keyPath);
}
OzoneVolume volume = getVolume();
+ OzoneBucket bucket = volume.getBucket(bucketName);
+ String bucketOwner = bucket.getOwner();
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucketOwner);
if (taggingMarker != null) {
s3GAction = S3GAction.PUT_OBJECT_TAGGING;
return putObjectTagging(volume, bucketName, keyPath, body);
@@ -265,7 +268,6 @@ public Response put(
boolean storageTypeDefault = StringUtils.isEmpty(storageType);
// Normal put object
- OzoneBucket bucket = volume.getBucket(bucketName);
ReplicationConfig replicationConfig =
getReplicationConfig(bucket, storageType, storageConfig);
@@ -428,6 +430,8 @@ public Response get(
S3GAction s3GAction = S3GAction.GET_KEY;
PerformanceStringBuilder perf = new PerformanceStringBuilder();
try {
+ OzoneBucket bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
if (taggingMarker != null) {
s3GAction = S3GAction.GET_OBJECT_TAGGING;
return getObjectTagging(bucketName, keyPath);
@@ -622,6 +626,8 @@ public Response head(
OzoneKey key;
try {
+ OzoneBucket bucket = getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
key = getClientProtocol().headS3Object(bucketName, keyPath);
isFile(keyPath, key);
@@ -743,6 +749,8 @@ public Response delete(
try {
OzoneVolume volume = getVolume();
+ OzoneBucket bucket = volume.getBucket(bucketName);
+ S3Owner.verifyBucketOwnerCondition(headers, bucketName, bucket.getOwner());
if (taggingMarker != null) {
s3GAction = S3GAction.DELETE_OBJECT_TAGGING;
return deleteObjectTagging(volume, bucketName, keyPath);
@@ -818,6 +826,7 @@ public Response initializeMultipartUpload(
try {
OzoneBucket ozoneBucket = getBucket(bucket);
+ S3Owner.verifyBucketOwnerCondition(headers, bucket, ozoneBucket.getOwner());
String storageType = headers.getHeaderString(STORAGE_CLASS_HEADER);
String storageConfig = headers.getHeaderString(CUSTOM_METADATA_HEADER_PREFIX + STORAGE_CONFIG_HEADER);
@@ -889,6 +898,9 @@ public Response completeMultipartUpload(@PathParam("bucket") String bucket,
OmMultipartUploadCompleteInfo omMultipartUploadCompleteInfo;
try {
+ OzoneBucket ozoneBucket = volume.getBucket(bucket);
+ S3Owner.verifyBucketOwnerCondition(headers, bucket, ozoneBucket.getOwner());
+
for (CompleteMultipartUploadRequest.Part part : partList) {
partsMap.put(part.getPartNumber(), part.getETag());
}
@@ -896,9 +908,7 @@ public Response completeMultipartUpload(@PathParam("bucket") String bucket,
LOG.debug("Parts map {}", partsMap);
}
- omMultipartUploadCompleteInfo = getClientProtocol()
- .completeMultipartUpload(volume.getName(), bucket, key, uploadID,
- partsMap);
+ omMultipartUploadCompleteInfo = ozoneBucket.completeMultipartUpload(key, uploadID, partsMap);
CompleteMultipartUploadResponse completeMultipartUploadResponse =
new CompleteMultipartUploadResponse();
completeMultipartUploadResponse.setBucket(bucket);
@@ -990,6 +1000,9 @@ private Response createMultipartKey(OzoneVolume volume, String bucket,
Pair result = parseSourceHeader(copyHeader);
String sourceBucket = result.getLeft();
String sourceKey = result.getRight();
+ String sourceBucketOwner = volume.getBucket(sourceBucket).getOwner();
+ S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, sourceBucket, sourceBucketOwner, bucket,
+ ozoneBucket.getOwner());
OzoneKeyDetails sourceKeyDetails = getClientProtocol().getKeyDetails(
volume.getName(), sourceBucket, sourceKey);
@@ -1236,6 +1249,10 @@ private CopyObjectResponse copyObject(OzoneVolume volume,
String sourceBucket = result.getLeft();
String sourceKey = result.getRight();
DigestInputStream sourceDigestInputStream = null;
+
+ String sourceBucketOwner = volume.getBucket(sourceBucket).getOwner();
+ // The destBucket owner has already been checked in the caller method
+ S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, sourceBucket, sourceBucketOwner, null, null);
try {
OzoneKeyDetails sourceKeyDetails = getClientProtocol().getKeyDetails(
volume.getName(), sourceBucket, sourceKey);
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Owner.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Owner.java
index bfec9038bcb0..f9baf0d5b7ff 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Owner.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Owner.java
@@ -17,10 +17,15 @@
package org.apache.hadoop.ozone.s3.endpoint;
+import javax.ws.rs.core.HttpHeaders;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
+import org.apache.hadoop.ozone.s3.util.S3Consts;
/**
* Represents an owner of S3 resources in the Ozone S3 compatibility layer.
@@ -80,4 +85,59 @@ public String toString() {
", id='" + id + '\'' +
'}';
}
+
+ /**
+ * Verify the bucket owner condition.
+ *
+ * @param headers HTTP headers
+ * @param bucketName bucket name
+ * @param bucketOwner bucket owner
+ * @throws OS3Exception if the expected bucket owner does not match
+ */
+ public static void verifyBucketOwnerCondition(HttpHeaders headers, String bucketName, String bucketOwner)
+ throws OS3Exception {
+ if (headers == null || bucketOwner == null) {
+ return;
+ }
+
+ final String expectedBucketOwner = headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER);
+
+ if (StringUtils.isEmpty(expectedBucketOwner)) {
+ return;
+ }
+ if (expectedBucketOwner.equals(bucketOwner)) {
+ return;
+ }
+ throw S3ErrorTable.newError(S3ErrorTable.BUCKET_OWNER_MISMATCH, bucketName);
+ }
+
+ /**
+ * Verify the bucket owner condition on copy operation.
+ *
+ * @param headers HTTP headers
+ * @param sourceBucketName source bucket name
+ * @param sourceOwner source bucket owner
+ * @param destBucketName dest bucket name
+ * @param destOwner destination bucket owner
+ * @throws OS3Exception if the expected source or destination bucket owner does not match
+ */
+ public static void verifyBucketOwnerConditionOnCopyOperation(HttpHeaders headers, String sourceBucketName,
+ String sourceOwner, String destBucketName,
+ String destOwner)
+ throws OS3Exception {
+ if (headers == null) {
+ return;
+ }
+
+ final String expectedSourceOwner = headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER);
+ final String expectedDestOwner = headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER);
+
+ if (expectedSourceOwner != null && sourceOwner != null && !sourceOwner.equals(expectedSourceOwner)) {
+ throw S3ErrorTable.newError(S3ErrorTable.BUCKET_OWNER_MISMATCH, sourceBucketName);
+ }
+
+ if (expectedDestOwner != null && destOwner != null && !destOwner.equals(expectedDestOwner)) {
+ throw S3ErrorTable.newError(S3ErrorTable.BUCKET_OWNER_MISMATCH, destBucketName);
+ }
+ }
}
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/exception/S3ErrorTable.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/exception/S3ErrorTable.java
index 200d9e8acb74..060ed83d1bcc 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/exception/S3ErrorTable.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/exception/S3ErrorTable.java
@@ -156,6 +156,10 @@ public final class S3ErrorTable {
"a valid custom EC storage config for if using STANDARD_IA.",
HTTP_BAD_REQUEST);
+ public static final OS3Exception BUCKET_OWNER_MISMATCH = new OS3Exception(
+ "Access Denied", "User doesn't have permission to access this resource due to a " +
+ "bucket ownership mismatch.", HTTP_FORBIDDEN);
+
private static Function generateInternalError =
e -> new OS3Exception("InternalError", e.getMessage(), HTTP_INTERNAL_ERROR);
diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
index 0e8b58dc80f2..f41013755030 100644
--- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
+++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/util/S3Consts.java
@@ -91,6 +91,11 @@ public final class S3Consts {
public static final Pattern TAG_REGEX_PATTERN = Pattern.compile("^([\\p{L}\\p{Z}\\p{N}_.:/=+\\-]*)$");
public static final String MP_PARTS_COUNT = "x-amz-mp-parts-count";
+ // Bucket owner condition headers
+ // See https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html
+ public static final String EXPECTED_BUCKET_OWNER_HEADER = "x-amz-expected-bucket-owner";
+ public static final String EXPECTED_SOURCE_BUCKET_OWNER_HEADER = "x-amz-source-expected-bucket-owner";
+
//Never Constructed
private S3Consts() {
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpointBuilder.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpointBuilder.java
index 1a3c4c492aa4..d192e17625a5 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpointBuilder.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/BucketEndpointBuilder.java
@@ -31,6 +31,7 @@ public BucketEndpointBuilder() {
public BucketEndpoint build() {
BucketEndpoint endpoint = super.build();
endpoint.setOzoneConfiguration(getConfig());
+ endpoint.setHeaders(getHeaders());
return endpoint;
}
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketAcl.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketAcl.java
index 1099fbea98cd..84bc414e37ee 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketAcl.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketAcl.java
@@ -67,6 +67,7 @@ public void setup() throws IOException {
bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(client)
+ .setHeaders(headers)
.build();
}
@@ -82,7 +83,7 @@ public void testGetAcl() throws Exception {
when(parameterMap.containsKey(ACL_MARKER)).thenReturn(true);
Response response =
bucketEndpoint.get(BUCKET_NAME, null, null, null, 0, null,
- null, null, null, ACL_MARKER, null, null, 0, headers);
+ null, null, null, ACL_MARKER, null, null, 0);
assertEquals(HTTP_OK, response.getStatus());
System.out.println(response.getEntity());
}
@@ -93,7 +94,7 @@ public void testSetAclWithNotSupportedGranteeType() throws Exception {
.thenReturn(S3Acl.ACLIdentityType.GROUP.getHeaderType() + "=root");
when(parameterMap.containsKey(ACL_MARKER)).thenReturn(true);
OS3Exception e = assertThrows(OS3Exception.class, () ->
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null));
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null));
assertEquals(e.getHttpCode(), HTTP_NOT_IMPLEMENTED);
}
@@ -103,7 +104,7 @@ public void testRead() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_READ))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -117,7 +118,7 @@ public void testWrite() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_WRITE))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -131,7 +132,7 @@ public void testReadACP() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_READ_CAP))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse =
bucketEndpoint.getAcl(BUCKET_NAME);
@@ -146,7 +147,7 @@ public void testWriteACP() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_WRITE_CAP))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -160,7 +161,7 @@ public void testFullControl() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_FULL_CONTROL))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -182,7 +183,7 @@ public void testCombination() throws Exception {
when(headers.getHeaderString(S3Acl.GRANT_FULL_CONTROL))
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(5, getResponse.getAclList().getGrantList().size());
@@ -195,7 +196,7 @@ public void testPutClearOldAcls() throws Exception {
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
// Put READ
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -212,7 +213,7 @@ public void testPutClearOldAcls() throws Exception {
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
//Put WRITE
response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, null);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, null);
assertEquals(HTTP_OK, response.getStatus());
getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(1, getResponse.getAclList().getGrantList().size());
@@ -230,7 +231,7 @@ public void testAclInBodyWithGroupUser() {
.getResourceAsStream("groupAccessControlList.xml");
when(parameterMap.containsKey(ACL_MARKER)).thenReturn(true);
assertThrows(OS3Exception.class, () -> bucketEndpoint.put(
- BUCKET_NAME, ACL_MARKER, headers, inputBody));
+ BUCKET_NAME, ACL_MARKER, inputBody));
}
@Test
@@ -239,7 +240,7 @@ public void testAclInBody() throws Exception {
.getResourceAsStream("userAccessControlList.xml");
when(parameterMap.containsKey(ACL_MARKER)).thenReturn(true);
Response response =
- bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, headers, inputBody);
+ bucketEndpoint.put(BUCKET_NAME, ACL_MARKER, inputBody);
assertEquals(HTTP_OK, response.getStatus());
S3BucketAcl getResponse = bucketEndpoint.getAcl(BUCKET_NAME);
assertEquals(2, getResponse.getAclList().getGrantList().size());
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketDelete.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketDelete.java
index c32b0e0ffd5c..54841563aefa 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketDelete.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketDelete.java
@@ -55,8 +55,6 @@ public void setup() throws Exception {
bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(clientStub)
.build();
-
-
}
@Test
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketList.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketList.java
index 3f0810dedee2..d55846c10af6 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketList.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketList.java
@@ -57,7 +57,7 @@ public void listRoot() throws OS3Exception, IOException {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100, "",
- null, null, null, null, null, null, 0, null)
+ null, null, null, null, null, null, 0)
.getEntity();
assertEquals(1, getBucketResponse.getCommonPrefixes().size());
@@ -82,7 +82,7 @@ public void listDir() throws OS3Exception, IOException {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100,
- "dir1", null, null, null, null, null, null, 0, null).getEntity();
+ "dir1", null, null, null, null, null, null, 0).getEntity();
assertEquals(1, getBucketResponse.getCommonPrefixes().size());
assertEquals("dir1/",
@@ -106,7 +106,7 @@ public void listSubDir() throws OS3Exception, IOException {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket
.get("b1", "/", null, null, 100, "dir1/", null,
- null, null, null, null, null, 0, null)
+ null, null, null, null, null, 0)
.getEntity();
assertEquals(1, getBucketResponse.getCommonPrefixes().size());
@@ -141,7 +141,7 @@ public void listObjectOwner() throws OS3Exception, IOException {
getBucket.setRequestIdentifier(new RequestIdentifier());
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100,
- "key", null, null, null, null, null, null, 0, null).getEntity();
+ "key", null, null, null, null, null, null, 0).getEntity();
assertEquals(2, getBucketResponse.getContents().size());
assertEquals(user1.getShortUserName(),
@@ -165,7 +165,7 @@ public void listWithPrefixAndDelimiter() throws OS3Exception, IOException {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100,
- "dir1", null, null, null, null, null, null, 0, null).getEntity();
+ "dir1", null, null, null, null, null, null, 0).getEntity();
assertEquals(3, getBucketResponse.getCommonPrefixes().size());
@@ -185,7 +185,7 @@ public void listWithPrefixAndDelimiter1() throws OS3Exception, IOException {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100,
- "", null, null, null, null, null, null, 0, null).getEntity();
+ "", null, null, null, null, null, null, 0).getEntity();
assertEquals(3, getBucketResponse.getCommonPrefixes().size());
assertEquals("file2", getBucketResponse.getContents().get(0)
@@ -206,7 +206,7 @@ public void listWithPrefixAndDelimiter2() throws OS3Exception, IOException {
getBucket.setRequestIdentifier(new RequestIdentifier());
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, 100, "dir1bh",
- null, "dir1/dir2/file2", null, null, null, null, 0, null).getEntity();
+ null, "dir1/dir2/file2", null, null, null, null, 0).getEntity();
assertEquals(2, getBucketResponse.getCommonPrefixes().size());
@@ -226,7 +226,7 @@ public void listWithPrefixAndEmptyStrDelimiter()
// Should behave the same if delimiter is null
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "", null, null, 100, "dir1/",
- null, null, null, null, null, null, 0, null).getEntity();
+ null, null, null, null, null, null, 0).getEntity();
assertEquals(0, getBucketResponse.getCommonPrefixes().size());
assertEquals(4, getBucketResponse.getContents().size());
@@ -258,7 +258,7 @@ public void listWithContinuationToken() throws OS3Exception, IOException {
// First time
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null, maxKeys,
- "", null, null, null, null, null, null, 0, null).getEntity();
+ "", null, null, null, null, null, null, 0).getEntity();
assertTrue(getBucketResponse.isTruncated());
assertEquals(2, getBucketResponse.getContents().size());
@@ -267,7 +267,7 @@ public void listWithContinuationToken() throws OS3Exception, IOException {
String continueToken = getBucketResponse.getNextToken();
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null, maxKeys,
- "", continueToken, null, null, null, null, null, 0, null).getEntity();
+ "", continueToken, null, null, null, null, null, 0).getEntity();
assertTrue(getBucketResponse.isTruncated());
assertEquals(2, getBucketResponse.getContents().size());
@@ -277,7 +277,7 @@ public void listWithContinuationToken() throws OS3Exception, IOException {
//3rd time
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null, maxKeys,
- "", continueToken, null, null, null, null, null, 0, null).getEntity();
+ "", continueToken, null, null, null, null, null, 0).getEntity();
assertFalse(getBucketResponse.isTruncated());
assertEquals(1, getBucketResponse.getContents().size());
@@ -310,7 +310,7 @@ public void listWithContinuationTokenDirBreak()
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, maxKeys,
- "test/", null, null, null, null, null, null, 0, null).getEntity();
+ "test/", null, null, null, null, null, null, 0).getEntity();
assertEquals(0, getBucketResponse.getContents().size());
assertEquals(2, getBucketResponse.getCommonPrefixes().size());
@@ -322,7 +322,7 @@ public void listWithContinuationTokenDirBreak()
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, maxKeys,
"test/", getBucketResponse.getNextToken(), null, null, null,
- null, null, 0, null).getEntity();
+ null, null, 0).getEntity();
assertEquals(1, getBucketResponse.getContents().size());
assertEquals(1, getBucketResponse.getCommonPrefixes().size());
assertEquals("test/dir3/",
@@ -354,7 +354,7 @@ public void listWithContinuationToken1() throws OS3Exception, IOException {
// First time
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, maxKeys,
- "dir", null, null, null, null, null, null, 0, null).getEntity();
+ "dir", null, null, null, null, null, null, 0).getEntity();
assertTrue(getBucketResponse.isTruncated());
assertEquals(2, getBucketResponse.getCommonPrefixes().size());
@@ -363,7 +363,7 @@ public void listWithContinuationToken1() throws OS3Exception, IOException {
String continueToken = getBucketResponse.getNextToken();
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, maxKeys,
- "dir", continueToken, null, null, null, null, null, 0, null).getEntity();
+ "dir", continueToken, null, null, null, null, null, 0).getEntity();
assertTrue(getBucketResponse.isTruncated());
assertEquals(2, getBucketResponse.getCommonPrefixes().size());
@@ -371,7 +371,7 @@ public void listWithContinuationToken1() throws OS3Exception, IOException {
continueToken = getBucketResponse.getNextToken();
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", "/", null, null, maxKeys,
- "dir", continueToken, null, null, null, null, null, 0, null).getEntity();
+ "dir", continueToken, null, null, null, null, null, 0).getEntity();
assertFalse(getBucketResponse.isTruncated());
assertEquals(1, getBucketResponse.getCommonPrefixes().size());
@@ -391,7 +391,7 @@ public void listWithContinuationTokenFail() throws IOException {
getBucket.setRequestIdentifier(new RequestIdentifier());
OS3Exception e = assertThrows(OS3Exception.class, () -> getBucket.get("b1",
- "/", null, null, 2, "dir", "random", null, null, null, null, null, 1000, null)
+ "/", null, null, 2, "dir", "random", null, null, null, null, null, 1000)
.getEntity(), "listWithContinuationTokenFail");
assertEquals("random", e.getResource());
assertEquals("Invalid Argument", e.getErrorMessage());
@@ -410,7 +410,7 @@ public void testStartAfter() throws IOException, OS3Exception {
ListObjectResponse getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null, 1000,
- null, null, null, null, null, null, null, 0, null).getEntity();
+ null, null, null, null, null, null, null, 0).getEntity();
assertFalse(getBucketResponse.isTruncated());
assertEquals(5, getBucketResponse.getContents().size());
@@ -421,14 +421,14 @@ public void testStartAfter() throws IOException, OS3Exception {
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null,
- 1000, null, null, startAfter, null, null, null, null, 0, null).getEntity();
+ 1000, null, null, startAfter, null, null, null, null, 0).getEntity();
assertFalse(getBucketResponse.isTruncated());
assertEquals(4, getBucketResponse.getContents().size());
getBucketResponse =
(ListObjectResponse) getBucket.get("b1", null, null, null,
- 1000, null, null, "random", null, null, null, null, 0, null).getEntity();
+ 1000, null, null, "random", null, null, null, null, 0).getEntity();
assertFalse(getBucketResponse.isTruncated());
assertEquals(0, getBucketResponse.getContents().size());
@@ -475,7 +475,7 @@ public void testEncodingType() throws IOException, OS3Exception {
ListObjectResponse response = (ListObjectResponse) getBucket.get(
"b1", delimiter, encodingType, null, 1000, prefix,
- null, startAfter, null, null, null, null, 0, null).getEntity();
+ null, startAfter, null, null, null, null, 0).getEntity();
// Assert encodingType == url.
// The Object name will be encoded by ObjectKeyNameAdapter
@@ -493,7 +493,7 @@ public void testEncodingType() throws IOException, OS3Exception {
response = (ListObjectResponse) getBucket.get(
"b1", delimiter, null, null, 1000, prefix,
- null, startAfter, null, null, null, null, 0, null).getEntity();
+ null, startAfter, null, null, null, null, 0).getEntity();
// Assert encodingType == null.
// The Object name will not be encoded by ObjectKeyNameAdapter
@@ -518,13 +518,14 @@ public void testEncodingTypeException() throws IOException {
getBucket.setRequestIdentifier(new RequestIdentifier());
OS3Exception e = assertThrows(OS3Exception.class, () -> getBucket.get(
"b1", null, "unSupportType", null, 1000, null,
- null, null, null, null, null, null, 0, null).getEntity());
+ null, null, null, null, null, null, 0).getEntity());
assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e.getCode());
}
@Test
public void testListObjectsWithInvalidMaxKeys() throws Exception {
OzoneClient client = createClientWithKeys("file1");
+ client.getObjectStore().createS3Bucket("bucket");
BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(client)
.build();
@@ -532,14 +533,14 @@ public void testListObjectsWithInvalidMaxKeys() throws Exception {
// maxKeys < 0
OS3Exception e1 = assertThrows(OS3Exception.class, () ->
bucketEndpoint.get("bucket", null, null, null, -1, null,
- null, null, null, null, null, null, 1000, null)
+ null, null, null, null, null, null, 1000)
);
assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e1.getCode());
// maxKeys == 0
OS3Exception e2 = assertThrows(OS3Exception.class, () ->
bucketEndpoint.get("bucket", null, null, null, 0, null,
- null, null, null, null, null, null, 1000, null)
+ null, null, null, null, null, null, 1000)
);
assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e2.getCode());
}
@@ -571,7 +572,7 @@ public void testListObjectsRespectsConfiguredMaxKeysLimit() throws Exception {
ListObjectResponse response = (ListObjectResponse)
bucketEndpoint.get("b1", null, null, null, requestedMaxKeys,
null, null, null, null, null, null, null,
- 1000, null).getEntity();
+ 1000).getEntity();
// Assert: The number of returned keys should be capped at the configured limit
assertEquals(Integer.parseInt(configuredMaxKeysLimit), response.getContents().size());
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketPut.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketPut.java
index 6f5d4d5d13bd..00543678234a 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketPut.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestBucketPut.java
@@ -57,7 +57,7 @@ public void setup() throws Exception {
@Test
public void testBucketFailWithAuthHeaderMissing() throws Exception {
try {
- bucketEndpoint.put(bucketName, null, null, null);
+ bucketEndpoint.put(bucketName, null, null);
} catch (OS3Exception ex) {
assertEquals(HTTP_NOT_FOUND, ex.getHttpCode());
assertEquals(MALFORMED_HEADER.getCode(), ex.getCode());
@@ -66,13 +66,13 @@ public void testBucketFailWithAuthHeaderMissing() throws Exception {
@Test
public void testBucketPut() throws Exception {
- Response response = bucketEndpoint.put(bucketName, null, null, null);
+ Response response = bucketEndpoint.put(bucketName, null, null);
assertEquals(200, response.getStatus());
assertNotNull(response.getLocation());
// Create-bucket on an existing bucket fails
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.put(
- bucketName, null, null, null));
+ bucketName, null, null));
assertEquals(HTTP_CONFLICT, e.getHttpCode());
assertEquals(BUCKET_ALREADY_EXISTS.getCode(), e.getCode());
}
@@ -80,7 +80,7 @@ public void testBucketPut() throws Exception {
@Test
public void testBucketFailWithInvalidHeader() throws Exception {
try {
- bucketEndpoint.put(bucketName, null, null, null);
+ bucketEndpoint.put(bucketName, null, null);
} catch (OS3Exception ex) {
assertEquals(HTTP_NOT_FOUND, ex.getHttpCode());
assertEquals(MALFORMED_HEADER.getCode(), ex.getCode());
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
index 9b34b6ec86ac..81f6853bf73f 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestPermissionCheck.java
@@ -130,13 +130,14 @@ public void testCreateBucket() throws IOException {
.setClient(client)
.build();
OS3Exception e = assertThrows(OS3Exception.class, () ->
- bucketEndpoint.put("bucketName", null, null, null));
+ bucketEndpoint.put("bucketName", null, null));
assertEquals(HTTP_FORBIDDEN, e.getHttpCode());
}
@Test
public void testDeleteBucket() throws IOException {
doThrow(exception).when(objectStore).deleteS3Bucket(anyString());
+ when(objectStore.getS3Bucket(anyString())).thenReturn(bucket);
BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(client)
.build();
@@ -168,7 +169,7 @@ public void testListKey() throws IOException {
.build();
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.get(
"bucketName", null, null, null, 1000,
- null, null, null, null, null, null, null, 0, null));
+ null, null, null, null, null, null, null, 0));
assertEquals(HTTP_FORBIDDEN, e.getHttpCode());
}
@@ -210,10 +211,11 @@ public void testGetAcl() throws Exception {
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(client)
+ .setHeaders(headers)
.build();
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.get(
"bucketName", null, null, null, 1000, null, null, null, null, "acl",
- null, null, 0, null), "Expected OS3Exception with FORBIDDEN http code.");
+ null, null, 0), "Expected OS3Exception with FORBIDDEN http code.");
assertEquals(HTTP_FORBIDDEN, e.getHttpCode());
}
@@ -232,9 +234,10 @@ public void testSetAcl() throws Exception {
.thenReturn(S3Acl.ACLIdentityType.USER.getHeaderType() + "=root");
BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder()
.setClient(client)
+ .setHeaders(headers)
.build();
try {
- bucketEndpoint.put("bucketName", "acl", headers, null);
+ bucketEndpoint.put("bucketName", "acl", null);
} catch (Exception e) {
assertTrue(e instanceof OS3Exception &&
((OS3Exception)e).getHttpCode() == HTTP_FORBIDDEN);
@@ -247,6 +250,7 @@ public void testSetAcl() throws Exception {
@Test
public void testGetKey() throws IOException {
when(client.getProxy()).thenReturn(clientProtocol);
+ when(objectStore.getS3Bucket(anyString())).thenReturn(bucket);
doThrow(exception).when(clientProtocol)
.getS3KeyDetails(anyString(), anyString());
ObjectEndpoint objectEndpoint = EndpointBuilder.newObjectEndpointBuilder()
@@ -281,6 +285,7 @@ public void testPutKey() throws IOException {
@Test
public void testDeleteKey() throws IOException {
when(objectStore.getS3Volume()).thenReturn(volume);
+ when(volume.getBucket(anyString())).thenReturn(bucket);
doThrow(exception).when(clientProtocol).deleteKey(anyString(), anyString(),
anyString(), anyBoolean());
ObjectEndpoint objectEndpoint = EndpointBuilder.newObjectEndpointBuilder()
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3Owner.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3Owner.java
new file mode 100644
index 000000000000..c47759e6369f
--- /dev/null
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3Owner.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.s3.endpoint;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import javax.ws.rs.core.HttpHeaders;
+import org.apache.hadoop.ozone.s3.exception.OS3Exception;
+import org.apache.hadoop.ozone.s3.exception.S3ErrorTable;
+import org.apache.hadoop.ozone.s3.util.S3Consts;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+
+/**
+ * Unit test class for testing logic related to TestS3Owner.
+ */
+public class TestS3Owner {
+
+ private static final String SOURCE_BUCKET_NAME = "source-bucket";
+ private static final String DEST_BUCKET_NAME = "dest-bucket";
+ private HttpHeaders headers;
+
+ @BeforeEach
+ public void setup() {
+ headers = mock(HttpHeaders.class);
+ }
+
+ @Test
+ public void testHeaderIsNull() {
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerCondition(null, SOURCE_BUCKET_NAME, "test"));
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(null, SOURCE_BUCKET_NAME, "test",
+ SOURCE_BUCKET_NAME, "test"));
+ }
+
+ @Test
+ public void testServerBucketOwnerIsNull() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER)).thenReturn("test");
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("test");
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerCondition(headers, SOURCE_BUCKET_NAME, null));
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, null,
+ SOURCE_BUCKET_NAME, "test"));
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, "test",
+ SOURCE_BUCKET_NAME, null));
+ }
+
+ @ParameterizedTest
+ @NullAndEmptySource
+ public void testS3OwnerNotEnable(String bucketOwnerHeader) {
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn(bucketOwnerHeader);
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerCondition(headers, SOURCE_BUCKET_NAME, "test"));
+
+ when(headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER)).thenReturn(bucketOwnerHeader);
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(null, SOURCE_BUCKET_NAME, "test",
+ SOURCE_BUCKET_NAME, "test"));
+ }
+
+ @Test
+ public void testClientBucketOwnerIsNull() {
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerCondition(headers, SOURCE_BUCKET_NAME, null));
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("test");
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, null,
+ SOURCE_BUCKET_NAME, "test"));
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, "test",
+ SOURCE_BUCKET_NAME, null));
+ }
+
+ @Test
+ public void testPassExpectedBucketOwner() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("test");
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerCondition(headers, SOURCE_BUCKET_NAME, "test"));
+ }
+
+ @Test
+ public void testFailExpectedBucketOwner() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("wrong");
+ OS3Exception exception =
+ assertThrows(OS3Exception.class, () -> S3Owner.verifyBucketOwnerCondition(headers, SOURCE_BUCKET_NAME, "test"));
+ assertThat(exception.getErrorMessage()).isEqualTo(S3ErrorTable.BUCKET_OWNER_MISMATCH.getErrorMessage());
+ }
+
+ @Test
+ public void testCopyOperationPass() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER)).thenReturn("source");
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("dest");
+ assertDoesNotThrow(() -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, "source",
+ SOURCE_BUCKET_NAME, "dest"));
+ }
+
+ @Test
+ public void testCopyOperationFailedOnSourceBucketOwner() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER)).thenReturn("source");
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("dest");
+ OS3Exception exception =
+ assertThrows(OS3Exception.class,
+ () -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, "wrong",
+ DEST_BUCKET_NAME, "dest"));
+ assertThat(exception.getErrorMessage()).isEqualTo(S3ErrorTable.BUCKET_OWNER_MISMATCH.getErrorMessage());
+ assertThat(exception.getResource()).isEqualTo(SOURCE_BUCKET_NAME);
+ }
+
+ @Test
+ public void testCopyOperationFailedOnDestBucketOwner() {
+ when(headers.getHeaderString(S3Consts.EXPECTED_SOURCE_BUCKET_OWNER_HEADER)).thenReturn("source");
+ when(headers.getHeaderString(S3Consts.EXPECTED_BUCKET_OWNER_HEADER)).thenReturn("dest");
+ OS3Exception exception =
+ assertThrows(OS3Exception.class,
+ () -> S3Owner.verifyBucketOwnerConditionOnCopyOperation(headers, SOURCE_BUCKET_NAME, "source",
+ DEST_BUCKET_NAME, "wrong"));
+ assertThat(exception.getErrorMessage()).isEqualTo(S3ErrorTable.BUCKET_OWNER_MISMATCH.getErrorMessage());
+ assertThat(exception.getResource()).isEqualTo(DEST_BUCKET_NAME);
+ }
+}
diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
index 63465ef7552e..8f570252d228 100644
--- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
+++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/metrics/TestS3GatewayMetrics.java
@@ -145,7 +145,7 @@ public void testGetBucketSuccess() throws Exception {
bucketEndpoint.get(bucketName, null,
null, null, 1000, null,
null, "random", null,
- null, null, null, 0, null).getEntity();
+ null, null, null, 0).getEntity();
long curMetric = metrics.getGetBucketSuccess();
assertEquals(1L, curMetric - oriMetric);
@@ -158,7 +158,7 @@ public void testGetBucketFailure() throws Exception {
// Searching for a bucket that does not exist
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.get(
"newBucket", null, null, null, 1000, null, null, "random", null,
- null, null, null, 0, null));
+ null, null, null, 0));
assertEquals(S3ErrorTable.NO_SUCH_BUCKET.getCode(), e.getCode());
assertEquals(S3ErrorTable.NO_SUCH_BUCKET.getErrorMessage(),
e.getErrorMessage());
@@ -170,7 +170,7 @@ public void testGetBucketFailure() throws Exception {
public void testCreateBucketSuccess() throws Exception {
long oriMetric = metrics.getCreateBucketSuccess();
- assertDoesNotThrow(() -> bucketEndpoint.put("newBucket", null, null, null));
+ assertDoesNotThrow(() -> bucketEndpoint.put("newBucket", null, null));
long curMetric = metrics.getCreateBucketSuccess();
assertEquals(1L, curMetric - oriMetric);
}
@@ -181,7 +181,7 @@ public void testCreateBucketFailure() throws Exception {
// Creating an error by trying to create a bucket that already exists
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.put(
- bucketName, null, null, null));
+ bucketName, null, null));
assertEquals(HTTP_CONFLICT, e.getHttpCode());
assertEquals(BUCKET_ALREADY_EXISTS.getCode(), e.getCode());
@@ -222,7 +222,7 @@ public void testGetAclSuccess() throws Exception {
Response response =
bucketEndpoint.get(bucketName, null, null,
null, 0, null, null,
- null, null, "acl", null, null, 0, null);
+ null, null, "acl", null, null, 0);
long curMetric = metrics.getGetAclSuccess();
assertEquals(HTTP_OK, response.getStatus());
assertEquals(1L, curMetric - oriMetric);
@@ -235,7 +235,7 @@ public void testGetAclFailure() throws Exception {
// Failing the getACL endpoint by applying ACL on a non-Existent Bucket
OS3Exception e = assertThrows(OS3Exception.class, () -> bucketEndpoint.get(
"random_bucket", null, null, null, 0, null,
- null, null, null, "acl", null, null, 0, null));
+ null, null, null, "acl", null, null, 0));
assertEquals(S3ErrorTable.NO_SUCH_BUCKET.getCode(), e.getCode());
assertEquals(S3ErrorTable.NO_SUCH_BUCKET.getErrorMessage(),
e.getErrorMessage());
@@ -251,7 +251,7 @@ public void testPutAclSuccess() throws Exception {
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");
- bucketEndpoint.put("b1", ACL_MARKER, headers, inputBody);
+ bucketEndpoint.put("b1", ACL_MARKER, inputBody);
inputBody.close();
long curMetric = metrics.getPutAclSuccess();
assertEquals(1L, curMetric - oriMetric);
@@ -265,7 +265,7 @@ public void testPutAclFailure() throws Exception {
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");
try {
- assertThrows(OS3Exception.class, () -> bucketEndpoint.put("unknown_bucket", ACL_MARKER, headers,
+ assertThrows(OS3Exception.class, () -> bucketEndpoint.put("unknown_bucket", ACL_MARKER,
inputBody));
} finally {
inputBody.close();