Skip to content

Commit 13f7067

Browse files
authored
Merge pull request #1659 from aws/feature/master/sigv4a
Adds support for S3 multi-region access points and Sigv4a signing
2 parents f63b331 + c205a07 commit 13f7067

File tree

113 files changed

+6742
-748
lines changed

Some content is hidden

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

113 files changed

+6742
-748
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "Amazon S3",
3+
"contributor": "",
4+
"type": "feature",
5+
"description": "Adds multi-region support for S3 access points as well as Sigv4 Asymmetric signing"
6+
}

build-tools/src/main/resources/software/amazon/awssdk/spotbugs-suppressions.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@
129129
<Bug pattern="EI_EXPOSE_REP" />
130130
</Match>
131131

132+
<Match>
133+
<Class name="software.amazon.awssdk.authcrt.signer.internal.SdkSigningResult" />
134+
<Method name="getSignature" />
135+
<Bug pattern="EI_EXPOSE_REP" />
136+
</Match>
137+
132138
<Match>
133139
<Class name="software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller" />
134140
<Method name="unmarshallStructured" />

core/arns/src/main/java/software/amazon/awssdk/arns/Arn.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.Objects;
1919
import java.util.Optional;
2020
import software.amazon.awssdk.annotations.SdkPublicApi;
21+
import software.amazon.awssdk.utils.StringUtils;
2122
import software.amazon.awssdk.utils.Validate;
2223
import software.amazon.awssdk.utils.builder.CopyableBuilder;
2324
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
@@ -106,14 +107,14 @@ public String service() {
106107
* @return The Region that the resource resides in.
107108
*/
108109
public Optional<String> region() {
109-
return Optional.ofNullable(region);
110+
return StringUtils.isEmpty(region) ? Optional.empty() : Optional.of(region);
110111
}
111112

112113
/**
113114
* @return The ID of the AWS account that owns the resource, without the hyphens.
114115
*/
115116
public Optional<String> accountId() {
116-
return Optional.ofNullable(accountId);
117+
return StringUtils.isEmpty(accountId) ? Optional.empty() : Optional.of(accountId);
117118
}
118119

119120
/**

core/arns/src/test/java/software/amazon/awssdk/arns/ArnTest.java

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ public void arnWithBasicResource_ParsesCorrectly() {
2929
Arn arn = Arn.fromString(arnString);
3030
assertThat(arn.partition()).isEqualTo("aws");
3131
assertThat(arn.service()).isEqualTo("s3");
32-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
33-
assertThat(arn.accountId()).isEqualTo(Optional.of("12345678910"));
32+
assertThat(arn.region()).hasValue("us-east-1");
33+
assertThat(arn.accountId()).hasValue("12345678910");
3434
assertThat(arn.resourceAsString()).isEqualTo("myresource");
3535
System.out.println(arn.resource());
3636
}
@@ -64,7 +64,7 @@ public void arnWithResourceTypeAndResource_ParsesCorrectly() {
6464
Arn arn = Arn.fromString(arnString);
6565
assertThat(arn.partition()).isEqualTo("aws");
6666
assertThat(arn.service()).isEqualTo("s3");
67-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
67+
assertThat(arn.region()).hasValue("us-east-1");
6868
assertThat(arn.resourceAsString()).isEqualTo("bucket:foobar");
6969

7070
verifyArnResource(arn.resource());
@@ -82,7 +82,7 @@ public void arnWithResourceTypeAndResourceAndQualifier_ParsesCorrectly() {
8282
Arn arn = Arn.fromString(arnString);
8383
assertThat(arn.partition()).isEqualTo("aws");
8484
assertThat(arn.service()).isEqualTo("s3");
85-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
85+
assertThat(arn.region()).hasValue("us-east-1");
8686
assertThat(arn.resourceAsString()).isEqualTo("bucket:foobar:1");
8787

8888

@@ -98,7 +98,7 @@ public void arnWithResourceTypeAndResource_SlashSplitter_ParsesCorrectly() {
9898
Arn arn = Arn.fromString(arnString);
9999
assertThat(arn.partition()).isEqualTo("aws");
100100
assertThat(arn.service()).isEqualTo("s3");
101-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
101+
assertThat(arn.region()).hasValue("us-east-1");
102102
assertThat(arn.resourceAsString()).isEqualTo("bucket/foobar");
103103
verifyArnResource(arn.resource());
104104
}
@@ -109,7 +109,7 @@ public void arnWithResourceTypeAndResourceAndQualifier_SlashSplitter_ParsesCorre
109109
Arn arn = Arn.fromString(arnString);
110110
assertThat(arn.partition()).isEqualTo("aws");
111111
assertThat(arn.service()).isEqualTo("s3");
112-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
112+
assertThat(arn.region()).hasValue("us-east-1");
113113
assertThat(arn.resourceAsString()).isEqualTo("bucket/foobar/1");
114114
verifyArnResource(arn.resource());
115115
assertThat(arn.resource().qualifier().get()).isEqualTo("1");
@@ -136,8 +136,8 @@ public void arnFromBuilder_ParsesCorrectly() {
136136

137137
assertThat(arn.partition()).isEqualTo("aws");
138138
assertThat(arn.service()).isEqualTo("s3");
139-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
140-
assertThat(arn.accountId()).isEqualTo(Optional.of("123456789012"));
139+
assertThat(arn.region()).hasValue("us-east-1");
140+
assertThat(arn.accountId()).hasValue("123456789012");
141141
assertThat(arn.resourceAsString()).isEqualTo("bucket:foobar:1");
142142
verifyArnResource(arn.resource());
143143
assertThat(arn.resource().qualifier()).isPresent();
@@ -156,13 +156,46 @@ public void arnResourceWithColonAndSlash_ParsesOnFirstSplitter() {
156156
.build();
157157
assertThat(arn.partition()).isEqualTo("aws");
158158
assertThat(arn.service()).isEqualTo("s3");
159-
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
160-
assertThat(arn.accountId()).isEqualTo(Optional.of("123456789012"));
159+
assertThat(arn.region()).hasValue("us-east-1");
160+
assertThat(arn.accountId()).hasValue("123456789012");
161161
assertThat(arn.resourceAsString()).isEqualTo(resourceWithColonAndSlash);
162162

163163
assertThat(arn.resource().resource()).isEqualTo("foobar/myobjectname");
164-
assertThat(arn.resource().qualifier()).isEqualTo(Optional.of("1"));
165-
assertThat(arn.resource().resourceType()).isEqualTo(Optional.of("object"));
164+
assertThat(arn.resource().qualifier()).hasValue("1");
165+
assertThat(arn.resource().resourceType()).hasValue("object");
166+
}
167+
168+
@Test
169+
public void arnWithoutRegion_ParsesCorrectly() {
170+
String arnString = "arn:aws:s3::123456789012:myresource";
171+
Arn arn = Arn.fromString(arnString);
172+
assertThat(arn.partition()).isEqualTo("aws");
173+
assertThat(arn.service()).isEqualTo("s3");
174+
assertThat(arn.region()).isEmpty();
175+
assertThat(arn.accountId()).hasValue("123456789012");
176+
assertThat(arn.resourceAsString()).isEqualTo("myresource");
177+
}
178+
179+
@Test
180+
public void arnWithoutAccountId_ParsesCorrectly() {
181+
String arnString = "arn:aws:s3:us-east-1::myresource";
182+
Arn arn = Arn.fromString(arnString);
183+
assertThat(arn.partition()).isEqualTo("aws");
184+
assertThat(arn.service()).isEqualTo("s3");
185+
assertThat(arn.region()).hasValue("us-east-1");
186+
assertThat(arn.accountId()).isEmpty();
187+
assertThat(arn.resourceAsString()).isEqualTo("myresource");
188+
}
189+
190+
@Test
191+
public void arnResourceContainingDots_ParsesCorrectly() {
192+
String arnString = "arn:aws:s3:us-east-1:12345678910:myresource:foobar.1";
193+
Arn arn = Arn.fromString(arnString);
194+
assertThat(arn.partition()).isEqualTo("aws");
195+
assertThat(arn.service()).isEqualTo("s3");
196+
assertThat(arn.region()).hasValue("us-east-1");
197+
assertThat(arn.accountId()).hasValue("12345678910");
198+
assertThat(arn.resourceAsString()).isEqualTo("myresource:foobar.1");
166199
}
167200

168201
@Test
@@ -205,6 +238,8 @@ public void hashCodeEquals_minimalProperties() {
205238
.build();
206239
Arn anotherArn = arn.toBuilder().build();
207240
assertThat(arn.hashCode()).isEqualTo(anotherArn.hashCode());
241+
assertThat(arn.region()).isEmpty();
242+
assertThat(arn.accountId()).isEmpty();
208243
assertThat(arn.equals(anotherArn)).isTrue();
209244
}
210245

core/auth-crt/pom.xml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License").
6+
~ You may not use this file except in compliance with the License.
7+
~ A copy of the License is located at
8+
~
9+
~ http://aws.amazon.com/apache2.0
10+
~
11+
~ or in the "license" file accompanying this file. This file is distributed
12+
~ on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
13+
~ express or implied. See the License for the specific language governing
14+
~ permissions and limitations under the License.
15+
-->
16+
17+
<project xmlns="http://maven.apache.org/POM/4.0.0"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
22+
<parent>
23+
<groupId>software.amazon.awssdk</groupId>
24+
<artifactId>core</artifactId>
25+
<version>2.17.33</version>
26+
</parent>
27+
28+
<artifactId>auth-crt</artifactId>
29+
<name>AWS Java SDK :: AuthCrt</name>
30+
<description>
31+
The AWS SDK for Java - AuthCrt module holds authentication types that are built on the AWS Common Runtime
32+
</description>
33+
<url>https://aws.amazon.com/sdkforjava</url>
34+
<dependencies>
35+
<dependency>
36+
<groupId>software.amazon.awssdk</groupId>
37+
<artifactId>annotations</artifactId>
38+
<version>${awsjavasdk.version}</version>
39+
</dependency>
40+
<dependency>
41+
<groupId>software.amazon.awssdk</groupId>
42+
<artifactId>utils</artifactId>
43+
<version>${awsjavasdk.version}</version>
44+
</dependency>
45+
<dependency>
46+
<groupId>software.amazon.awssdk</groupId>
47+
<artifactId>sdk-core</artifactId>
48+
<version>${awsjavasdk.version}</version>
49+
</dependency>
50+
<dependency>
51+
<groupId>software.amazon.awssdk</groupId>
52+
<artifactId>regions</artifactId>
53+
<version>${awsjavasdk.version}</version>
54+
</dependency>
55+
<dependency>
56+
<groupId>software.amazon.awssdk</groupId>
57+
<artifactId>http-client-spi</artifactId>
58+
<version>${awsjavasdk.version}</version>
59+
</dependency>
60+
<dependency>
61+
<groupId>software.amazon.awssdk</groupId>
62+
<artifactId>auth</artifactId>
63+
<version>${awsjavasdk.version}</version>
64+
</dependency>
65+
<dependency>
66+
<groupId>software.amazon.awssdk.crt</groupId>
67+
<artifactId>aws-crt</artifactId>
68+
<version>${awscrt.version}</version>
69+
</dependency>
70+
71+
<dependency>
72+
<groupId>junit</groupId>
73+
<artifactId>junit</artifactId>
74+
<scope>test</scope>
75+
</dependency>
76+
<dependency>
77+
<groupId>com.github.tomakehurst</groupId>
78+
<artifactId>wiremock</artifactId>
79+
<scope>test</scope>
80+
</dependency>
81+
<dependency>
82+
<groupId>log4j</groupId>
83+
<artifactId>log4j</artifactId>
84+
<scope>test</scope>
85+
</dependency>
86+
<dependency>
87+
<groupId>org.slf4j</groupId>
88+
<artifactId>slf4j-log4j12</artifactId>
89+
<scope>test</scope>
90+
</dependency>
91+
<dependency>
92+
<groupId>software.amazon.awssdk</groupId>
93+
<artifactId>test-utils</artifactId>
94+
<scope>test</scope>
95+
</dependency>
96+
<dependency>
97+
<groupId>commons-io</groupId>
98+
<artifactId>commons-io</artifactId>
99+
<scope>test</scope>
100+
</dependency>
101+
<dependency>
102+
<groupId>commons-lang</groupId>
103+
<artifactId>commons-lang</artifactId>
104+
<scope>test</scope>
105+
</dependency>
106+
<dependency>
107+
<groupId>org.assertj</groupId>
108+
<artifactId>assertj-core</artifactId>
109+
<scope>test</scope>
110+
</dependency>
111+
<dependency>
112+
<groupId>org.hamcrest</groupId>
113+
<artifactId>hamcrest-all</artifactId>
114+
<scope>test</scope>
115+
</dependency>
116+
<dependency>
117+
<groupId>org.mockito</groupId>
118+
<artifactId>mockito-core</artifactId>
119+
<scope>test</scope>
120+
</dependency>
121+
<dependency>
122+
<groupId>nl.jqno.equalsverifier</groupId>
123+
<artifactId>equalsverifier</artifactId>
124+
<scope>test</scope>
125+
</dependency>
126+
<dependency>
127+
<groupId>org.unitils</groupId>
128+
<artifactId>unitils-core</artifactId>
129+
<scope>test</scope>
130+
</dependency>
131+
<dependency>
132+
<groupId>io.reactivex.rxjava2</groupId>
133+
<artifactId>rxjava</artifactId>
134+
<scope>test</scope>
135+
</dependency>
136+
</dependencies>
137+
<build>
138+
<plugins>
139+
<plugin>
140+
<groupId>org.apache.maven.plugins</groupId>
141+
<artifactId>maven-jar-plugin</artifactId>
142+
<configuration>
143+
<archive>
144+
<manifestEntries>
145+
<Automatic-Module-Name>software.amazon.awssdk.authcrt</Automatic-Module-Name>
146+
</manifestEntries>
147+
</archive>
148+
</configuration>
149+
</plugin>
150+
</plugins>
151+
</build>
152+
</project>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 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+
16+
package software.amazon.awssdk.authcrt.signer;
17+
18+
import software.amazon.awssdk.annotations.Immutable;
19+
import software.amazon.awssdk.annotations.SdkPublicApi;
20+
import software.amazon.awssdk.annotations.ThreadSafe;
21+
import software.amazon.awssdk.authcrt.signer.internal.DefaultAwsCrtS3V4aSigner;
22+
import software.amazon.awssdk.core.signer.Presigner;
23+
import software.amazon.awssdk.core.signer.Signer;
24+
25+
/**
26+
* Enables signing and presigning for S3 using Sigv4a (Asymmetric Sigv4) through an external API call to the AWS CRT
27+
* (Common RunTime) library.
28+
* <p/><b>S3 signing specifics</b><br>
29+
* For S3, the header "x-amz-sha256" must always be set for a request.
30+
* <p/>
31+
* S3 signs the payload signing if:
32+
* <ol>
33+
* <li> there's a body and an insecure protocol (HTTP) is used.</li>
34+
* <li> explicitly asked to via configuration/interceptor.</li>
35+
* </ol>
36+
* Otherwise, the body hash value will be UNSIGNED-PAYLOAD.
37+
* <p/>
38+
* See <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html">
39+
* Amazon S3 Sigv4 documentation</a> for more detailed information.
40+
*/
41+
@SdkPublicApi
42+
@Immutable
43+
@ThreadSafe
44+
public interface AwsCrtS3V4aSigner extends Signer, Presigner {
45+
46+
/**
47+
* Create a default AwsS34aSigner.
48+
*/
49+
static AwsCrtS3V4aSigner create() {
50+
return DefaultAwsCrtS3V4aSigner.create();
51+
}
52+
}

0 commit comments

Comments
 (0)