Skip to content

Commit 272d438

Browse files
author
Bennett Lynch
authored
[Hackathon] Add extension method: verifyBucketOwnership (#3076)
* [Hackathon] Add extension method: verifyBucketOwnership
1 parent 04b351e commit 272d438

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

services/s3/src/it/java/software/amazon/awssdk/services/s3/extensions/DefaultS3ExtensionIntegrationTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
package software.amazon.awssdk.services.s3.extensions;
1717

1818
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatCode;
20+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
1921
import static software.amazon.awssdk.testutils.service.S3BucketUtils.temporaryBucketName;
2022

2123
import java.io.File;
2224
import java.io.IOException;
2325
import org.junit.AfterClass;
2426
import org.junit.BeforeClass;
2527
import org.junit.Test;
28+
import software.amazon.awssdk.core.exception.SdkClientException;
2629
import software.amazon.awssdk.services.s3.S3IntegrationTestBase;
2730
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
2831
import software.amazon.awssdk.testutils.RandomTempFile;
@@ -86,4 +89,17 @@ public void objectDoesNotExistSync() {
8689
public void objectDoesNotExistAsync() {
8790
assertThat(s3Async.doesObjectExist(BUCKET, "noexist").join()).isFalse();
8891
}
92+
93+
@Test
94+
public void verifyBucketOwnership_userOwnsBucket() {
95+
assertThatCode(() -> s3.verifyBucketOwnership(BUCKET)).doesNotThrowAnyException();
96+
}
97+
98+
@Test
99+
public void verifyBucketOwnership_userDoesNotOwnBucket() {
100+
assertThatThrownBy(() -> s3.verifyBucketOwnership(temporaryBucketName("noexist")))
101+
.isInstanceOf(SdkClientException.class)
102+
.hasMessage("Bucket ownership verification failed.");
103+
}
104+
89105
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/extensions/S3ClientSdkExtension.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,22 @@ default URL getUrl(Consumer<GetUrlRequest.Builder> getUrlRequest) {
124124
default S3Presigner presigner() {
125125
return S3Presigner.create();
126126
}
127+
128+
/**
129+
* Validate that the currently configured AWS Account is the owner of a given S3 bucket. Because Amazon S3 identifies buckets
130+
* based on their names, an application that uses an incorrect bucket name in a request could inadvertently perform operations
131+
* against a different bucket than expected.
132+
* <p>
133+
* Because buckets can be deleted and re-created at any time, this method should only be used when you know that the bucket in
134+
* question will not be deleted after its ownership is verified. For more robust protection, you should include the {@code
135+
* expectedBucketOwner} parameter with all eligible requests. For more information, see:
136+
* <p>
137+
* https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucket-owner-condition.html
138+
*
139+
* @param bucket the bucket to verify ownership
140+
*/
141+
@SdkExtensionMethod
142+
default void verifyBucketOwnership(String bucket) {
143+
new DefaultS3ClientSdkExtension((S3Client) this).verifyBucketOwnership(bucket);
144+
}
127145
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/extensions/DefaultS3ClientSdkExtension.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
package software.amazon.awssdk.services.s3.internal.extensions;
1717

1818
import software.amazon.awssdk.annotations.SdkInternalApi;
19+
import software.amazon.awssdk.core.exception.SdkClientException;
1920
import software.amazon.awssdk.services.s3.S3Client;
2021
import software.amazon.awssdk.services.s3.extensions.S3ClientSdkExtension;
22+
import software.amazon.awssdk.services.s3.model.Bucket;
2123
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
2224
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
2325
import software.amazon.awssdk.utils.Validate;
@@ -53,4 +55,17 @@ public boolean doesObjectExist(String bucket, String key) {
5355
return false;
5456
}
5557
}
58+
59+
@Override
60+
public void verifyBucketOwnership(String bucket) {
61+
Validate.notEmpty(bucket, "bucket");
62+
boolean isBucketOwner = s3.listBuckets()
63+
.buckets()
64+
.stream()
65+
.map(Bucket::name)
66+
.anyMatch(b -> b.equals(bucket));
67+
if (!isBucketOwner) {
68+
throw SdkClientException.create("Bucket ownership verification failed.");
69+
}
70+
}
5671
}

0 commit comments

Comments
 (0)