Skip to content

Commit 88c2c7a

Browse files
authored
Merge pull request #692 from aws/finks/westeros-final
Adding support for S3 Access Points
2 parents 01bbdf2 + 41d1b82 commit 88c2c7a

File tree

47 files changed

+3290
-49
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+3290
-49
lines changed

bom/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@
4444
<artifactId>annotations</artifactId>
4545
<version>${awsjavasdk.version}</version>
4646
</dependency>
47+
<dependency>
48+
<groupId>software.amazon.awssdk</groupId>
49+
<artifactId>arns</artifactId>
50+
<version>${awsjavasdk.version}</version>
51+
</dependency>
4752
<dependency>
4853
<groupId>software.amazon.awssdk</groupId>
4954
<artifactId>auth</artifactId>

core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/handler/AwsClientHandlerUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,9 @@ static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext
8181
.putAttribute(SdkInternalExecutionAttribute.IS_FULL_DUPLEX, executionParams.isFullDuplex())
8282
.putAttribute(SdkExecutionAttribute.CLIENT_TYPE, clientConfig.option(SdkClientOption.CLIENT_TYPE))
8383
.putAttribute(SdkExecutionAttribute.SERVICE_NAME, clientConfig.option(SdkClientOption.SERVICE_NAME))
84-
.putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName());
84+
.putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName())
85+
.putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN,
86+
clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN));
8587

8688
ExecutionInterceptorChain executionInterceptorChain =
8789
new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS));

core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@
3434

3535
<modules>
3636
<module>annotations</module>
37+
<module>arns</module>
3738
<module>auth</module>
3839
<module>sdk-core</module>
3940
<module>aws-core</module>
4041
<module>profiles</module>
4142
<module>regions</module>
4243
<module>protocols</module>
43-
<module>arns</module>
4444
</modules>
4545

4646
<dependencyManagement>

core/regions/src/main/java/software/amazon/awssdk/regions/PartitionMetadata.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,15 @@ public interface PartitionMetadata {
7171
static PartitionMetadata of(String partition) {
7272
return MetadataLoader.partitionMetadata(partition);
7373
}
74+
75+
/**
76+
* Retrieves the partition metadata for a given region.
77+
*
78+
* @param region The region to get the partition metadata for.
79+
*
80+
* @return {@link PartitionMetadata} for the given region.
81+
*/
82+
static PartitionMetadata of(Region region) {
83+
return MetadataLoader.partitionMetadata(region);
84+
}
7485
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,7 @@ public enum SdkSystemSetting implements SystemSetting {
149149
* the SDK to use the {@code s3.us-east-1.amazonaws.com} endpoint when using the {@code US_EAST_1} region instead of
150150
* the global {@code s3.amazonaws.com}. Using the regional endpoint is disabled by default.
151151
*/
152-
AWS_S3_US_EAST_1_REGIONAL_ENDPOINT(null, null)
153-
154-
;
152+
AWS_S3_US_EAST_1_REGIONAL_ENDPOINT(null, null);
155153

156154
private final String systemProperty;
157155
private final String defaultValue;

core/sdk-core/src/main/java/software/amazon/awssdk/core/client/builder/SdkDefaultClientBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ private SdkClientConfiguration mergeGlobalDefaults(SdkClientConfiguration config
195195
}
196196

197197
/**
198-
* Optionally overidden by child implementations to derive implementation-specific configuration from the default-applied
199-
* configuration. (eg. AWS's endpoint, derived from the region).
198+
* Optionally overridden by child implementations to derive implementation-specific configuration from the
199+
* default-applied configuration. (eg. AWS's endpoint, derived from the region).
200200
*/
201201
protected SdkClientConfiguration finalizeChildConfiguration(SdkClientConfiguration configuration) {
202202
return configuration;
@@ -309,6 +309,7 @@ public final B endpointOverride(URI endpointOverride) {
309309
Validate.paramNotNull(endpointOverride, "endpointOverride");
310310
Validate.paramNotNull(endpointOverride.getScheme(), "The URI scheme of endpointOverride");
311311
clientConfiguration.option(SdkClientOption.ENDPOINT, endpointOverride);
312+
clientConfiguration.option(SdkClientOption.ENDPOINT_OVERRIDDEN, true);
312313
return thisBuilder();
313314
}
314315

core/sdk-core/src/main/java/software/amazon/awssdk/core/client/config/SdkClientOption.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import software.amazon.awssdk.annotations.SdkProtectedApi;
2424
import software.amazon.awssdk.core.ClientType;
2525
import software.amazon.awssdk.core.ServiceConfiguration;
26-
import software.amazon.awssdk.core.client.builder.SdkClientBuilder;
2726
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
2827
import software.amazon.awssdk.core.retry.RetryPolicy;
2928
import software.amazon.awssdk.http.SdkHttpClient;
@@ -52,10 +51,17 @@ public final class SdkClientOption<T> extends ClientOption<T> {
5251
new SdkClientOption<>(new UnsafeValueType(List.class));
5352

5453
/**
55-
* @see SdkClientBuilder#endpointOverride(URI)
54+
* The effective endpoint the client is configured to make requests to. If the client has been configured with
55+
* an endpoint override then this value will be the provided endpoint value.
5656
*/
5757
public static final SdkClientOption<URI> ENDPOINT = new SdkClientOption<>(URI.class);
5858

59+
/**
60+
* A flag that when set to true indicates the endpoint stored in {@link SdkClientOption#ENDPOINT} was a customer
61+
* supplied value and not generated by the client based on Region metadata.
62+
*/
63+
public static final SdkClientOption<Boolean> ENDPOINT_OVERRIDDEN = new SdkClientOption<>(Boolean.class);
64+
5965
/**
6066
* Service-specific configuration used by some services, like S3.
6167
*/

core/sdk-core/src/main/java/software/amazon/awssdk/core/interceptor/SdkExecutionAttribute.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ public class SdkExecutionAttribute {
4545
public static final ExecutionAttribute<ClientType> CLIENT_TYPE = new ExecutionAttribute<>("ClientType");
4646

4747
public static final ExecutionAttribute<String> OPERATION_NAME = new ExecutionAttribute<>("OperationName");
48+
49+
/**
50+
* If true indicates that the configured endpoint of the client is a value that was supplied as an override and not
51+
* generated from regional metadata.
52+
*/
53+
public static final ExecutionAttribute<Boolean> ENDPOINT_OVERRIDDEN = new ExecutionAttribute<>("EndpointOverride");
4854

4955
protected SdkExecutionAttribute() {
5056
}

services/ec2/src/main/java/software/amazon/awssdk/services/ec2/transform/internal/GeneratePreSignUrlInterceptor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@
4545
@SdkInternalApi
4646
public final class GeneratePreSignUrlInterceptor implements ExecutionInterceptor {
4747

48+
private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost");
49+
4850
private static final AwsEc2ProtocolFactory PROTOCOL_FACTORY = AwsEc2ProtocolFactory
4951
.builder()
5052
// Need an endpoint to marshall but this will be overwritten in modifyHttpRequest
5153
.clientConfiguration(SdkClientConfiguration.builder()
52-
.option(SdkClientOption.ENDPOINT, URI.create("http://localhost"))
54+
.option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST)
5355
.build())
5456
.build();
5557

services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@
4848
@SdkInternalApi
4949
public abstract class RdsPresignInterceptor<T extends RdsRequest> implements ExecutionInterceptor {
5050

51+
private static final URI CUSTOM_ENDPOINT_LOCALHOST = URI.create("http://localhost");
52+
5153
protected static final AwsQueryProtocolFactory PROTOCOL_FACTORY = AwsQueryProtocolFactory
5254
.builder()
5355
// Need an endpoint to marshall but this will be overwritten in modifyHttpRequest
5456
.clientConfiguration(SdkClientConfiguration.builder()
55-
.option(SdkClientOption.ENDPOINT, URI.create("http://localhost"))
57+
.option(SdkClientOption.ENDPOINT, CUSTOM_ENDPOINT_LOCALHOST)
5658
.build())
5759
.build();
5860

services/s3/pom.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@
5656
<artifactId>protocol-core</artifactId>
5757
<version>${awsjavasdk.version}</version>
5858
</dependency>
59+
<dependency>
60+
<groupId>software.amazon.awssdk</groupId>
61+
<artifactId>arns</artifactId>
62+
<version>${awsjavasdk.version}</version>
63+
</dependency>
64+
<dependency>
65+
<groupId>software.amazon.awssdk</groupId>
66+
<artifactId>profiles</artifactId>
67+
<version>${awsjavasdk.version}</version>
68+
</dependency>
5969
<!-- Test Dependencies -->
6070
<dependency>
6171
<artifactId>commons-io</artifactId>
@@ -80,6 +90,12 @@
8090
<version>${awsjavasdk.version}</version>
8191
<scope>test</scope>
8292
</dependency>
93+
<dependency>
94+
<artifactId>s3control</artifactId>
95+
<groupId>software.amazon.awssdk</groupId>
96+
<version>${awsjavasdk.version}</version>
97+
<scope>test</scope>
98+
</dependency>
8399
<dependency>
84100
<groupId>org.apache.commons</groupId>
85101
<artifactId>commons-lang3</artifactId>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
package software.amazon.awssdk.services.s3;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
import static software.amazon.awssdk.testutils.service.S3BucketUtils.temporaryBucketName;
19+
20+
import java.util.StringJoiner;
21+
import org.junit.BeforeClass;
22+
import org.junit.Test;
23+
import software.amazon.awssdk.core.sync.RequestBody;
24+
import software.amazon.awssdk.regions.Region;
25+
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
26+
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
27+
import software.amazon.awssdk.services.s3control.S3ControlClient;
28+
import software.amazon.awssdk.services.s3control.model.S3ControlException;
29+
import software.amazon.awssdk.services.sts.StsClient;
30+
31+
public class AccessPointsIntegrationTest extends S3IntegrationTestBase {
32+
33+
private static final String BUCKET = temporaryBucketName(AclIntegrationTest.class);
34+
35+
private static final String AP_NAME = "java-sdk";
36+
37+
private static final String KEY = "some-key";
38+
39+
private static S3ControlClient s3control;
40+
41+
private static StsClient sts;
42+
43+
private static String accountId;
44+
45+
@BeforeClass
46+
public static void setupFixture() {
47+
createBucket(BUCKET);
48+
49+
s3control = S3ControlClient.builder()
50+
.region(Region.US_WEST_2)
51+
.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN)
52+
.build();
53+
54+
sts = StsClient.builder()
55+
.region(Region.US_WEST_2)
56+
.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN)
57+
.build();
58+
59+
accountId = sts.getCallerIdentity().account();
60+
61+
try {
62+
s3control.createAccessPoint(r -> r.accountId(accountId)
63+
.bucket(BUCKET)
64+
.name(AP_NAME));
65+
} catch (S3ControlException e) {
66+
// Do nothing as the access point is already created
67+
}
68+
}
69+
70+
@Test
71+
public void transfer_Succeeds_UsingAccessPoint() {
72+
StringJoiner apArn = new StringJoiner(":");
73+
apArn.add("arn").add("aws").add("s3").add("us-west-2").add(accountId).add("accesspoint").add(AP_NAME);
74+
75+
s3.putObject(PutObjectRequest.builder()
76+
.bucket(apArn.toString())
77+
.key(KEY)
78+
.build(), RequestBody.fromString("helloworld"));
79+
80+
String objectContent = s3.getObjectAsBytes(GetObjectRequest.builder()
81+
.bucket(apArn.toString())
82+
.key(KEY)
83+
.build()).asUtf8String();
84+
85+
assertThat(objectContent).isEqualTo("helloworld");
86+
}
87+
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Configuration.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import software.amazon.awssdk.annotations.SdkPublicApi;
2121
import software.amazon.awssdk.annotations.ThreadSafe;
2222
import software.amazon.awssdk.core.ServiceConfiguration;
23+
import software.amazon.awssdk.services.s3.internal.usearnregion.UseArnRegionProviderChain;
2324
import software.amazon.awssdk.services.s3.model.PutBucketAccelerateConfigurationRequest;
2425
import software.amazon.awssdk.utils.builder.CopyableBuilder;
2526
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -28,6 +29,8 @@
2829
@Immutable
2930
@ThreadSafe
3031
public final class S3Configuration implements ServiceConfiguration, ToCopyableBuilder<S3Configuration.Builder, S3Configuration> {
32+
private static final UseArnRegionProviderChain USE_ARN_REGION_PROVIDER_CHAIN = UseArnRegionProviderChain.create();
33+
3134
/**
3235
* The default setting for use of path style addressing.
3336
*/
@@ -60,6 +63,7 @@ public final class S3Configuration implements ServiceConfiguration, ToCopyableBu
6063
private final boolean dualstackEnabled;
6164
private final boolean checksumValidationEnabled;
6265
private final boolean chunkedEncodingEnabled;
66+
private final boolean useArnRegionEnabled;
6367

6468
private S3Configuration(DefaultS3ServiceConfigurationBuilder builder) {
6569
this.dualstackEnabled = resolveBoolean(builder.dualstackEnabled, DEFAULT_DUALSTACK_ENABLED);
@@ -70,6 +74,8 @@ private S3Configuration(DefaultS3ServiceConfigurationBuilder builder) {
7074
throw new IllegalArgumentException("Accelerate mode cannot be used with path style addressing");
7175
}
7276
this.chunkedEncodingEnabled = resolveBoolean(builder.chunkedEncodingEnabled, DEFAULT_CHUNKED_ENCODING_ENABLED);
77+
this.useArnRegionEnabled = Boolean.TRUE.equals(builder.useArnRegionEnabled) ? builder.useArnRegionEnabled :
78+
resolveUseArnRegionEnabled();
7379
}
7480

7581
/**
@@ -153,16 +159,31 @@ public boolean chunkedEncodingEnabled() {
153159
return chunkedEncodingEnabled;
154160
}
155161

162+
/**
163+
* Returns whether the client is allowed to make cross-region calls when an S3 Access Point ARN has a different
164+
* region to the one configured on the client.
165+
* <p>
166+
* @return True if a different region in the ARN can be used.
167+
*/
168+
public boolean useArnRegionEnabled() {
169+
return useArnRegionEnabled;
170+
}
171+
156172
private boolean resolveBoolean(Boolean customerSuppliedValue, boolean defaultValue) {
157173
return customerSuppliedValue == null ? defaultValue : customerSuppliedValue;
158174
}
159175

176+
private boolean resolveUseArnRegionEnabled() {
177+
return USE_ARN_REGION_PROVIDER_CHAIN.resolveUseArnRegion().orElse(false);
178+
}
179+
160180
@Override
161181
public Builder toBuilder() {
162182
return builder()
163183
.dualstackEnabled(dualstackEnabled)
164184
.accelerateModeEnabled(accelerateModeEnabled)
165-
.pathStyleAccessEnabled(pathStyleAccessEnabled);
185+
.pathStyleAccessEnabled(pathStyleAccessEnabled)
186+
.useArnRegionEnabled(useArnRegionEnabled);
166187
}
167188

168189
@NotThreadSafe
@@ -226,6 +247,15 @@ public interface Builder extends CopyableBuilder<Builder, S3Configuration> { //
226247
* @see S3Configuration#chunkedEncodingEnabled()
227248
*/
228249
Builder chunkedEncodingEnabled(Boolean chunkedEncodingEnabled);
250+
251+
/**
252+
* If an S3 resource ARN is passed in as the target of an S3 operation that has a different region to the one
253+
* the client was configured with, this flag must be set to 'true' to permit the client to make a
254+
* cross-region call to the region specified in the ARN otherwise an exception will be thrown.
255+
*
256+
* @see S3Configuration#useArnRegionEnabled()
257+
*/
258+
Builder useArnRegionEnabled(Boolean useArnRegionEnabled);
229259
}
230260

231261
private static final class DefaultS3ServiceConfigurationBuilder implements Builder {
@@ -235,6 +265,7 @@ private static final class DefaultS3ServiceConfigurationBuilder implements Build
235265
private Boolean pathStyleAccessEnabled;
236266
private Boolean checksumValidationEnabled;
237267
private Boolean chunkedEncodingEnabled;
268+
private Boolean useArnRegionEnabled;
238269

239270
public Builder dualstackEnabled(Boolean dualstackEnabled) {
240271
this.dualstackEnabled = dualstackEnabled;
@@ -281,6 +312,15 @@ public void setChunkedEncodingEnabled(Boolean chunkedEncodingEnabled) {
281312
chunkedEncodingEnabled(chunkedEncodingEnabled);
282313
}
283314

315+
public Builder useArnRegionEnabled(Boolean useArnRegionEnabled) {
316+
this.useArnRegionEnabled = useArnRegionEnabled;
317+
return this;
318+
}
319+
320+
public void setUseArnRegionEnabled(Boolean useArnRegionEnabled) {
321+
useArnRegionEnabled(useArnRegionEnabled);
322+
}
323+
284324
public S3Configuration build() {
285325
return new S3Configuration(this);
286326
}

0 commit comments

Comments
 (0)