Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JavaV2: Check if bucket exists example that provides replacement for V1's doesBucketExistV2 #7057

Merged
merged 3 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .doc_gen/metadata/s3_metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3524,3 +3524,20 @@ s3_Scenario_DownloadS3Directory:
- s3.tm.java2.download-s3-directories.main
services:
s3: {}
s3_Scenario_DoesBucketExist:
title: Check if a bucket exists
title_abbrev: Check if a bucket exists
synopsis: check if a bucket exists.
category: Scenarios
languages:
Java:
versions:
- sdk_version: 2
github: javav2/example_code/s3
sdkguide:
excerpts:
- description: You can use the following <code>doesBucketExists</code> method as a replacement for the the &Java; V1 <ulink url="https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#doesBucketExistV2-java.lang.String-">AmazonS3Client#doesBucketExistV2(String)</ulink> method.
snippet_tags:
- s3.java2.does-bucket-exist-main
services:
s3: {GetBucketAcl}
13 changes: 13 additions & 0 deletions javav2/example_code/s3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ Code excerpts that show you how to call individual service functions.
Code examples that show you how to accomplish a specific task by calling multiple
functions within the same service.

- [Check if a bucket exists](src/main/java/com/example/s3/DoesBucketExist.java)
- [Delete incomplete multipart uploads](src/main/java/com/example/s3/AbortMultipartUploadExamples.java)
- [Download S3 'directories'](src/main/java/com/example/s3/transfermanager/S3DirectoriesDownloader.java)
- [Download objects to a local directory](src/main/java/com/example/s3/transfermanager/DownloadToDirectory.java)
Expand Down Expand Up @@ -129,6 +130,18 @@ This example shows you how to do the following:
<!--custom.basics.s3_Scenario_GettingStarted.end-->


#### Check if a bucket exists

This example shows you how to check if a bucket exists.


<!--custom.scenario_prereqs.s3_Scenario_DoesBucketExist.start-->
<!--custom.scenario_prereqs.s3_Scenario_DoesBucketExist.end-->


<!--custom.scenarios.s3_Scenario_DoesBucketExist.start-->
<!--custom.scenarios.s3_Scenario_DoesBucketExist.end-->

#### Delete incomplete multipart uploads

This example shows you how to how to delete or stop incomplete Amazon S3 multipart uploads.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package com.example.s3;
// snippet-start:[s3.java2.does-bucket-exist-main]

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.http.HttpStatusCode;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.utils.Validate;

public class DoesBucketExist {
private static final Logger logger = LoggerFactory.getLogger(DoesBucketExist.class);

public static void main(String[] args) {
DoesBucketExist doesBucketExist = new DoesBucketExist();

final S3Client s3SyncClient = S3Client.builder().build();
final String bucketName = "amzn-s3-demo-bucket"; // Change to the bucket name that you want to check.

boolean exists = doesBucketExist.doesBucketExist(bucketName, s3SyncClient);
logger.info("Bucket exists: {}", exists);
}

/**
* Checks if the specified bucket exists. Amazon S3 buckets are named in a global namespace; use this method to
* determine if a specified bucket name already exists, and therefore can't be used to create a new bucket.
* <p>
* Internally this method uses the <a
* href="https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html#getBucketAcl(java.util.function.Consumer)">S3Client.getBucketAcl(String)</a>
* operation to determine whether the bucket exists.
* <p>
* This method is equivalent to the AWS SDK for Java V1's <a
* href="https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html#doesBucketExistV2-java.lang.String-">AmazonS3Client#doesBucketExistV2(String)</a>.
*
* @param bucketName The name of the bucket to check.
* @param s3SyncClient An <code>S3Client</code> instance. The method checks for the bucket in the AWS Region
* configured on the instance.
* @return The value true if the specified bucket exists in Amazon S3; the value false if there is no bucket in
* Amazon S3 with that name.
*/
public boolean doesBucketExist(String bucketName, S3Client s3SyncClient) {
try {
Validate.notEmpty(bucketName, "The bucket name must not be null or an empty string.", "");
s3SyncClient.getBucketAcl(r -> r.bucket(bucketName));
return true;
} catch (AwsServiceException ase) {
// A redirect error or an AccessDenied exception means the bucket exists but it's not in this region
// or we don't have permissions to it.
if ((ase.statusCode() == HttpStatusCode.MOVED_PERMANENTLY) || "AccessDenied".equals(ase.awsErrorDetails().errorCode())) {
return true;
}
if (ase.statusCode() == HttpStatusCode.NOT_FOUND) {
return false;
}
throw ase;
}
}
}
// snippet-end:[s3.java2.does-bucket-exist-main]
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

public class S3DirectoriesDownloader {
private static final Logger logger = LoggerFactory.getLogger(S3DirectoriesDownloader.class);
public final String bucketName = "amzn-s3-demo-bucket" + UUID.randomUUID(); // Change bucket name.
public final String bucketName = "junk-s3-demo-bucket" + UUID.randomUUID(); // Change bucket name.
public URI destinationPathURI;
private final Set<String> downloadedFileNameSet = new HashSet<>();
private final String destinationDirName = "downloadDirectory";
Expand Down
22 changes: 22 additions & 0 deletions javav2/example_code/s3/src/main/resources/xml_testing.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<AccessControlList>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser">
<DisplayName>owner</DisplayName>
<ID>dad784318ac45facc6a8c74b9b44f18afd317c85fa8776eeb2b000c8942bc8d9</ID>
</Grantee>
<Permission>FULL_CONTROL</Permission>
</Grant>
<Grant>
<Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group">
<DisplayName>my-grantee</DisplayName>
<URI>http://acs.amazonaws.com/groups/global/AuthenticatedUsers</URI>
</Grantee>
<Permission>READ_ACP</Permission>
</Grant>
</AccessControlList>
<Owner>
<ID>dad784318ac45facc6a8c74b9b44f18afd317c85fa8776eeb2b000c8942bc8d9</ID>
</Owner>
</AccessControlPolicy>
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package com.example.s3;
//

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import software.amazon.awssdk.policybuilder.iam.IamConditionKey;
import software.amazon.awssdk.policybuilder.iam.IamConditionOperator;
import software.amazon.awssdk.policybuilder.iam.IamEffect;
import software.amazon.awssdk.policybuilder.iam.IamPolicy;
import software.amazon.awssdk.policybuilder.iam.IamPrincipalType;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.iam.IamClient;
import software.amazon.awssdk.services.iam.model.PutRolePolicyResponse;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;

import java.util.List;
import java.util.UUID;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class DoesBucketExistTest {
private static final String ROLE_NAME = "minimal-s3-perms-role";
private static final String POLICY_NAME = "minimum-s3-ability-policy";
private static final IamClient iamClient = IamClient.builder().build();

@Test
@Tag("IntegrationTest")
void doesBucketExist_exists_but_not_in_client_region_should_return_true() {

S3Client usWestS3Client = S3Client.builder().region(Region.US_WEST_2).build();
final String bucketName = "my-us-west2-bucket-" + UUID.randomUUID();
createBucket(usWestS3Client, bucketName);

DoesBucketExist doesBucketExist = new DoesBucketExist();
S3Client euCentralS3Client = S3Client.builder().region(Region.EU_CENTRAL_1).build();
boolean exists = doesBucketExist.doesBucketExist(bucketName, euCentralS3Client);
assertTrue(exists);

deleteBucket(usWestS3Client, bucketName);
}

@Test
@Tag("IntegrationTest")
void doesBucketExist_does_not_exist_should_return_false() {

DoesBucketExist doesBucketExist = new DoesBucketExist();
final String bucketName = "xx-xx-xxxx-xxxx" + UUID.randomUUID();

boolean exists = doesBucketExist.doesBucketExist(bucketName, S3Client.create());
assertFalse(exists);
}

@Test
@Tag("IntegrationTest")
void doesBucketExist_returns_true_when_bucket_exists_but_caller_does_not_have_permission() {
StsClient stsClient = StsClient.create();
createAssumableRole(stsClient);

S3Client s3Client = S3Client.create();
final String bucketName = "my-bucket-" + UUID.randomUUID();
createBucket(s3Client, bucketName);

try {

String roleArn = iamClient.getRole(b -> b.roleName(ROLE_NAME)).role().arn();

S3Client s3ClientWithoutPermission = S3Client.builder()
.credentialsProvider(StsAssumeRoleCredentialsProvider.builder()
.stsClient(stsClient)
.refreshRequest(arr -> arr
.roleArn(roleArn)
.roleSessionName("test-session"))
.build())
.build();
DoesBucketExist doesBucketExist = new DoesBucketExist();
boolean existsButNoAccess = doesBucketExist.doesBucketExist(bucketName, s3ClientWithoutPermission);
assertTrue(existsButNoAccess);

boolean exists = doesBucketExist.doesBucketExist("non-existent-bucket" + UUID.randomUUID(), s3ClientWithoutPermission);
assertFalse(exists);
} finally {
deleteBucket(s3Client, bucketName);
deleteRole();

}
}

private static void createBucket(S3Client s3Client, String bucketName) {
s3Client.createBucket(b -> b.bucket(bucketName));
s3Client.waiter().waitUntilBucketExists(b -> b.bucket(bucketName));
}

private static void deleteBucket(S3Client s3Client, String bucketName) {
s3Client.deleteBucket(b -> b.bucket(bucketName));
s3Client.waiter().waitUntilBucketNotExists(b -> b.bucket(bucketName));
}


private static void createAssumableRole(StsClient stsClient) {
final String accountID = stsClient.getCallerIdentity().account();

IamPolicy trustIamPolicyForAnyoneInSameAccount = IamPolicy.builder()
.addStatement(statement -> statement
.effect(IamEffect.ALLOW)
.addPrincipal(principal -> principal
.type(IamPrincipalType.AWS)
.id("arn:aws:iam::" + accountID + ":root")
)
.addAction("sts:AssumeRole")
.addConditions(IamConditionOperator.STRING_EQUALS,
IamConditionKey.create("aws:PrincipalType"),
List.of("User", "AssumedRole")
).addConditions(IamConditionOperator.STRING_LIKE,
"aws:userId",
List.of("AIDAX*", "AROA*:*", "AIDA*:*"))
)
.build();

iamClient.createRole(crb -> crb
.roleName(ROLE_NAME)
.assumeRolePolicyDocument(trustIamPolicyForAnyoneInSameAccount.toJson())
);

IamPolicy getBucketLocationOnlyPolicy = IamPolicy.builder()
.addStatement(statement -> statement
.effect(IamEffect.ALLOW)
.addAction("s3:GetBucketLocation")
.addResource("arn:aws:s3:::*")
)
.build();

iamClient.putRolePolicy(prprb -> prprb
.roleName(ROLE_NAME)
.policyName(POLICY_NAME)
.policyDocument(getBucketLocationOnlyPolicy.toJson()));

// Add a delay for the role to propagate.
try {
Thread.sleep(8000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}

}

private static void deleteRole(){

iamClient.deleteRolePolicy(drbrb -> drbrb
.roleName(ROLE_NAME)
.policyName(POLICY_NAME));

iamClient.deleteRole(drb -> drb
.roleName(ROLE_NAME)
);
}
}

Loading