Skip to content

Commit

Permalink
Merge pull request #1659 from aws/feature/master/sigv4a
Browse files Browse the repository at this point in the history
Adds support for S3 multi-region access points and Sigv4a signing
  • Loading branch information
cenedhryn authored Sep 2, 2021
2 parents f63b331 + c205a07 commit 13f7067
Show file tree
Hide file tree
Showing 113 changed files with 6,742 additions and 748 deletions.
6 changes: 6 additions & 0 deletions .changes/next-release/feature-AmazonS3-155bd4c.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"category": "Amazon S3",
"contributor": "",
"type": "feature",
"description": "Adds multi-region support for S3 access points as well as Sigv4 Asymmetric signing"
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,12 @@
<Bug pattern="EI_EXPOSE_REP" />
</Match>

<Match>
<Class name="software.amazon.awssdk.authcrt.signer.internal.SdkSigningResult" />
<Method name="getSignature" />
<Bug pattern="EI_EXPOSE_REP" />
</Match>

<Match>
<Class name="software.amazon.awssdk.protocols.json.internal.unmarshall.JsonProtocolUnmarshaller" />
<Method name="unmarshallStructured" />
Expand Down
5 changes: 3 additions & 2 deletions core/arns/src/main/java/software/amazon/awssdk/arns/Arn.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Objects;
import java.util.Optional;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.utils.StringUtils;
import software.amazon.awssdk.utils.Validate;
import software.amazon.awssdk.utils.builder.CopyableBuilder;
import software.amazon.awssdk.utils.builder.ToCopyableBuilder;
Expand Down Expand Up @@ -106,14 +107,14 @@ public String service() {
* @return The Region that the resource resides in.
*/
public Optional<String> region() {
return Optional.ofNullable(region);
return StringUtils.isEmpty(region) ? Optional.empty() : Optional.of(region);
}

/**
* @return The ID of the AWS account that owns the resource, without the hyphens.
*/
public Optional<String> accountId() {
return Optional.ofNullable(accountId);
return StringUtils.isEmpty(accountId) ? Optional.empty() : Optional.of(accountId);
}

/**
Expand Down
59 changes: 47 additions & 12 deletions core/arns/src/test/java/software/amazon/awssdk/arns/ArnTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public void arnWithBasicResource_ParsesCorrectly() {
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.accountId()).isEqualTo(Optional.of("12345678910"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.accountId()).hasValue("12345678910");
assertThat(arn.resourceAsString()).isEqualTo("myresource");
System.out.println(arn.resource());
}
Expand Down Expand Up @@ -64,7 +64,7 @@ public void arnWithResourceTypeAndResource_ParsesCorrectly() {
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.resourceAsString()).isEqualTo("bucket:foobar");

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


Expand All @@ -98,7 +98,7 @@ public void arnWithResourceTypeAndResource_SlashSplitter_ParsesCorrectly() {
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.resourceAsString()).isEqualTo("bucket/foobar");
verifyArnResource(arn.resource());
}
Expand All @@ -109,7 +109,7 @@ public void arnWithResourceTypeAndResourceAndQualifier_SlashSplitter_ParsesCorre
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.resourceAsString()).isEqualTo("bucket/foobar/1");
verifyArnResource(arn.resource());
assertThat(arn.resource().qualifier().get()).isEqualTo("1");
Expand All @@ -136,8 +136,8 @@ public void arnFromBuilder_ParsesCorrectly() {

assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.accountId()).isEqualTo(Optional.of("123456789012"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.accountId()).hasValue("123456789012");
assertThat(arn.resourceAsString()).isEqualTo("bucket:foobar:1");
verifyArnResource(arn.resource());
assertThat(arn.resource().qualifier()).isPresent();
Expand All @@ -156,13 +156,46 @@ public void arnResourceWithColonAndSlash_ParsesOnFirstSplitter() {
.build();
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEqualTo(Optional.of("us-east-1"));
assertThat(arn.accountId()).isEqualTo(Optional.of("123456789012"));
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.accountId()).hasValue("123456789012");
assertThat(arn.resourceAsString()).isEqualTo(resourceWithColonAndSlash);

assertThat(arn.resource().resource()).isEqualTo("foobar/myobjectname");
assertThat(arn.resource().qualifier()).isEqualTo(Optional.of("1"));
assertThat(arn.resource().resourceType()).isEqualTo(Optional.of("object"));
assertThat(arn.resource().qualifier()).hasValue("1");
assertThat(arn.resource().resourceType()).hasValue("object");
}

@Test
public void arnWithoutRegion_ParsesCorrectly() {
String arnString = "arn:aws:s3::123456789012:myresource";
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).isEmpty();
assertThat(arn.accountId()).hasValue("123456789012");
assertThat(arn.resourceAsString()).isEqualTo("myresource");
}

@Test
public void arnWithoutAccountId_ParsesCorrectly() {
String arnString = "arn:aws:s3:us-east-1::myresource";
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.accountId()).isEmpty();
assertThat(arn.resourceAsString()).isEqualTo("myresource");
}

@Test
public void arnResourceContainingDots_ParsesCorrectly() {
String arnString = "arn:aws:s3:us-east-1:12345678910:myresource:foobar.1";
Arn arn = Arn.fromString(arnString);
assertThat(arn.partition()).isEqualTo("aws");
assertThat(arn.service()).isEqualTo("s3");
assertThat(arn.region()).hasValue("us-east-1");
assertThat(arn.accountId()).hasValue("12345678910");
assertThat(arn.resourceAsString()).isEqualTo("myresource:foobar.1");
}

@Test
Expand Down Expand Up @@ -205,6 +238,8 @@ public void hashCodeEquals_minimalProperties() {
.build();
Arn anotherArn = arn.toBuilder().build();
assertThat(arn.hashCode()).isEqualTo(anotherArn.hashCode());
assertThat(arn.region()).isEmpty();
assertThat(arn.accountId()).isEmpty();
assertThat(arn.equals(anotherArn)).isTrue();
}

Expand Down
152 changes: 152 additions & 0 deletions core/auth-crt/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
~
~ Licensed under the Apache License, Version 2.0 (the "License").
~ You may not use this file except in compliance with the License.
~ A copy of the License is located at
~
~ http://aws.amazon.com/apache2.0
~
~ or in the "license" file accompanying this file. This file 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.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>software.amazon.awssdk</groupId>
<artifactId>core</artifactId>
<version>2.17.33</version>
</parent>

<artifactId>auth-crt</artifactId>
<name>AWS Java SDK :: AuthCrt</name>
<description>
The AWS SDK for Java - AuthCrt module holds authentication types that are built on the AWS Common Runtime
</description>
<url>https://aws.amazon.com/sdkforjava</url>
<dependencies>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>annotations</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>utils</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>regions</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>http-client-spi</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<version>${awsjavasdk.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk.crt</groupId>
<artifactId>aws-crt</artifactId>
<version>${awscrt.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>test-utils</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.unitils</groupId>
<artifactId>unitils-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Automatic-Module-Name>software.amazon.awssdk.authcrt</Automatic-Module-Name>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.awssdk.authcrt.signer;

import software.amazon.awssdk.annotations.Immutable;
import software.amazon.awssdk.annotations.SdkPublicApi;
import software.amazon.awssdk.annotations.ThreadSafe;
import software.amazon.awssdk.authcrt.signer.internal.DefaultAwsCrtS3V4aSigner;
import software.amazon.awssdk.core.signer.Presigner;
import software.amazon.awssdk.core.signer.Signer;

/**
* Enables signing and presigning for S3 using Sigv4a (Asymmetric Sigv4) through an external API call to the AWS CRT
* (Common RunTime) library.
* <p/><b>S3 signing specifics</b><br>
* For S3, the header "x-amz-sha256" must always be set for a request.
* <p/>
* S3 signs the payload signing if:
* <ol>
* <li> there's a body and an insecure protocol (HTTP) is used.</li>
* <li> explicitly asked to via configuration/interceptor.</li>
* </ol>
* Otherwise, the body hash value will be UNSIGNED-PAYLOAD.
* <p/>
* See <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html">
* Amazon S3 Sigv4 documentation</a> for more detailed information.
*/
@SdkPublicApi
@Immutable
@ThreadSafe
public interface AwsCrtS3V4aSigner extends Signer, Presigner {

/**
* Create a default AwsS34aSigner.
*/
static AwsCrtS3V4aSigner create() {
return DefaultAwsCrtS3V4aSigner.create();
}
}
Loading

0 comments on commit 13f7067

Please sign in to comment.