Upgrade to AWS SDK v2.

Original pull request: gh-693.
Closes gh-253
This commit is contained in:
Max Fortun
2022-04-06 16:10:23 -04:00
committed by Mark Paluch
parent 3d0b909b5a
commit 8f6ada53f8
5 changed files with 63 additions and 58 deletions

View File

@@ -164,8 +164,8 @@
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>

View File

@@ -21,11 +21,16 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.List;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import software.amazon.awssdk.auth.signer.Aws4Signer;
import software.amazon.awssdk.auth.signer.params.Aws4SignerParams;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain;
import com.amazonaws.DefaultRequest;
import com.amazonaws.auth.AWS4Signer;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.http.HttpMethodName;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.logging.Log;
@@ -45,20 +50,20 @@ import org.springframework.web.client.RestOperations;
/**
* AWS IAM authentication using signed HTTP requests to query the current identity.
* <p>
* AWS IAM authentication creates a {@link AWS4Signer signed} HTTP request that is
* AWS IAM authentication creates a {@link Aws4Signer signed} HTTP request that is
* executed by Vault to get the identity of the signer using AWS STS
* {@literal GetCallerIdentity}. A signature requires
* {@link com.amazonaws.auth.AWSCredentials} to calculate the signature.
* {@link com.amazonaws.auth.AwsCredentials} to calculate the signature.
* <p>
* This authentication requires AWS' Java SDK to sign request parameters and calculate the
* signature key. Using an appropriate {@link com.amazonaws.auth.AWSCredentialsProvider}
* signature key. Using an appropriate {@link com.amazonaws.auth.AwsCredentialsProvider}
* allows authentication within AWS-EC2 instances with an assigned profile, within ECS and
* Lambda instances.
*
* @author Mark Paluch
* @since 1.1
* @see AwsIamAuthenticationOptions
* @see com.amazonaws.auth.AWSCredentialsProvider
* @see com.amazonaws.auth.AwsCredentialsProvider
* @see RestOperations
* @see <a href="https://www.vaultproject.io/docs/auth/aws.html">Auth Backend: aws
* (IAM)</a>
@@ -99,7 +104,7 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
/**
* Creates a {@link AuthenticationSteps} for AWS-IAM authentication given
* {@link AwsIamAuthenticationOptions}. The resulting {@link AuthenticationSteps}
* reuse eagerly-fetched {@link AWSCredentials} to prevent blocking I/O during
* reuse eagerly-fetched {@link AwsCredentials} to prevent blocking I/O during
* authentication.
* @param options must not be {@literal null}.
* @return {@link AuthenticationSteps} for AWS-IAM authentication.
@@ -109,13 +114,13 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
Assert.notNull(options, "AwsIamAuthenticationOptions must not be null");
AWSCredentials credentials = options.getCredentialsProvider().getCredentials();
AwsCredentials credentials = options.getCredentialsProvider().resolveCredentials();
return createAuthenticationSteps(options, credentials);
}
protected static AuthenticationSteps createAuthenticationSteps(AwsIamAuthenticationOptions options,
AWSCredentials credentials) {
AwsCredentials credentials) {
return AuthenticationSteps.fromSupplier(() -> createRequestBody(options, credentials)) //
.login(AuthenticationUtil.getLoginPath(options.getPath()));
@@ -128,7 +133,7 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
@Override
public AuthenticationSteps getAuthenticationSteps() {
return createAuthenticationSteps(this.options, this.options.getCredentialsProvider().getCredentials());
return createAuthenticationSteps(this.options, this.options.getCredentialsProvider().resolveCredentials());
}
@SuppressWarnings("unchecked")
@@ -169,7 +174,7 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
* @return the map containing body key-value pairs.
*/
protected static Map<String, String> createRequestBody(AwsIamAuthenticationOptions options) {
return createRequestBody(options, options.getCredentialsProvider().getCredentials());
return createRequestBody(options, options.getCredentialsProvider().resolveCredentials());
}
/**
@@ -179,7 +184,7 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
* @return the map containing body key-value pairs.
*/
private static Map<String, String> createRequestBody(AwsIamAuthenticationOptions options,
AWSCredentials credentials) {
AwsCredentials credentials) {
Map<String, String> login = new HashMap<>();
@@ -197,26 +202,25 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
return login;
}
private static String getSignedHeaders(AwsIamAuthenticationOptions options, AWSCredentials credentials) {
private static String getSignedHeaders(AwsIamAuthenticationOptions options, AwsCredentials credentials) {
Map<String, String> headers = createIamRequestHeaders(options);
Map<String, List<String>> headers = createIamRequestHeaders(options);
AWS4Signer signer = new AWS4Signer();
SdkHttpFullRequest.Builder builder = SdkHttpFullRequest.builder()
.contentStreamProvider(() -> new ByteArrayInputStream(REQUEST_BODY.getBytes())).headers(headers)
.method(SdkHttpMethod.POST).uri(options.getEndpointUri());
SdkHttpFullRequest request = builder.build();
DefaultRequest<String> request = new DefaultRequest<>("sts");
request.setContent(new ByteArrayInputStream(REQUEST_BODY.getBytes()));
request.setHeaders(headers);
request.setHttpMethod(HttpMethodName.POST);
request.setEndpoint(options.getEndpointUri());
signer.setServiceName(request.getServiceName());
signer.sign(request, credentials);
Region region = DefaultAwsRegionProviderChain.builder().build().getRegion();
Aws4Signer signer = Aws4Signer.create();
Aws4SignerParams signerParams = Aws4SignerParams.builder().awsCredentials(credentials).signingName("sts")
.signingRegion(region).build();
SdkHttpFullRequest signedRequest = signer.sign(request, signerParams);
Map<String, Object> map = new LinkedHashMap<>();
for (Entry<String, String> entry : request.getHeaders().entrySet()) {
map.put(entry.getKey(), Collections.singletonList(entry.getValue()));
for (Entry<String, List<String>> entry : signedRequest.headers().entrySet()) {
map.put(entry.getKey(), entry.getValue());
}
try {
@@ -227,15 +231,15 @@ public class AwsIamAuthentication implements ClientAuthentication, Authenticatio
}
}
private static Map<String, String> createIamRequestHeaders(AwsIamAuthenticationOptions options) {
private static Map<String, List<String>> createIamRequestHeaders(AwsIamAuthenticationOptions options) {
Map<String, String> headers = new LinkedHashMap<>();
Map<String, List<String>> headers = new LinkedHashMap<>();
headers.put(HttpHeaders.CONTENT_LENGTH, "" + REQUEST_BODY.length());
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
headers.put(HttpHeaders.CONTENT_LENGTH, Collections.singletonList("" + REQUEST_BODY.length()));
headers.put(HttpHeaders.CONTENT_TYPE, Collections.singletonList(MediaType.APPLICATION_FORM_URLENCODED_VALUE));
if (StringUtils.hasText(options.getServerId())) {
headers.put("X-Vault-AWS-IAM-Server-ID", options.getServerId());
headers.put("X-Vault-AWS-IAM-Server-ID", Collections.singletonList(options.getServerId()));
}
return headers;

View File

@@ -17,9 +17,9 @@ package org.springframework.vault.authentication;
import java.net.URI;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -27,7 +27,7 @@ import org.springframework.util.Assert;
/**
* Authentication options for {@link AwsIamAuthentication}.
* <p>
* Authentication options provide the path, a {@link AWSCredentialsProvider} optional role
* Authentication options provide the path, a {@link AwsCredentialsProvider} optional role
* and server name ({@literal Vault-AWS-IAM-Server-ID} header).
* {@link AwsIamAuthenticationOptions} can be constructed using {@link #builder()}.
* Instances of this class are immutable once constructed.
@@ -49,7 +49,7 @@ public class AwsIamAuthenticationOptions {
/**
* Credential provider.
*/
private final AWSCredentialsProvider credentialsProvider;
private final AwsCredentialsProvider credentialsProvider;
/**
* Name of the role against which the login is being attempted. If role is not
@@ -71,7 +71,7 @@ public class AwsIamAuthenticationOptions {
*/
private final URI endpointUri;
private AwsIamAuthenticationOptions(String path, AWSCredentialsProvider credentialsProvider, @Nullable String role,
private AwsIamAuthenticationOptions(String path, AwsCredentialsProvider credentialsProvider, @Nullable String role,
@Nullable String serverId, URI endpointUri) {
this.path = path;
@@ -98,7 +98,7 @@ public class AwsIamAuthenticationOptions {
/**
* @return the credentials provider to obtain AWS credentials.
*/
public AWSCredentialsProvider getCredentialsProvider() {
public AwsCredentialsProvider getCredentialsProvider() {
return this.credentialsProvider;
}
@@ -147,7 +147,7 @@ public class AwsIamAuthenticationOptions {
private String path = DEFAULT_AWS_AUTHENTICATION_PATH;
@Nullable
private AWSCredentialsProvider credentialsProvider;
private AwsCredentialsProvider credentialsProvider;
@Nullable
private String role;
@@ -176,29 +176,29 @@ public class AwsIamAuthenticationOptions {
/**
* Configure static AWS credentials, required to calculate the signature. Either
* use static credentials or provide a
* {@link #credentialsProvider(AWSCredentialsProvider) credentials provider}.
* {@link #credentialsProvider(AwsCredentialsProvider) credentials provider}.
* @param credentials must not be {@literal null}.
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
* @see #credentialsProvider(AWSCredentialsProvider)
* @see #credentialsProvider(AwsCredentialsProvider)
*/
public AwsIamAuthenticationOptionsBuilder credentials(AWSCredentials credentials) {
public AwsIamAuthenticationOptionsBuilder credentials(AwsCredentials credentials) {
Assert.notNull(credentials, "Credentials must not be null");
return credentialsProvider(new AWSStaticCredentialsProvider(credentials));
return credentialsProvider(StaticCredentialsProvider.create(credentials));
}
/**
* Configure an {@link AWSCredentialsProvider}, required to calculate the
* signature. Alternatively, configure static {@link #credentials(AWSCredentials)
* Configure an {@link AwsCredentialsProvider}, required to calculate the
* signature. Alternatively, configure static {@link #credentials(AwsCredentials)
* credentials}.
* @param credentialsProvider must not be {@literal null}.
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
* @see #credentials(AWSCredentials)
* @see #credentials(AwsCredentials)
*/
public AwsIamAuthenticationOptionsBuilder credentialsProvider(AWSCredentialsProvider credentialsProvider) {
public AwsIamAuthenticationOptionsBuilder credentialsProvider(AwsCredentialsProvider credentialsProvider) {
Assert.notNull(credentialsProvider, "AWSCredentialsProvider must not be null");
Assert.notNull(credentialsProvider, "AwsCredentialsProvider must not be null");
this.credentialsProvider = credentialsProvider;
return this;

View File

@@ -17,7 +17,8 @@ package org.springframework.vault.authentication;
import java.time.Duration;
import com.amazonaws.auth.BasicAWSCredentials;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -67,7 +68,7 @@ class AwsIamAuthenticationUnitTests {
+ "}"));
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder().role("foo-role")
.credentials(new BasicAWSCredentials("foo", "bar")).build();
.credentials(AwsBasicCredentials.create("foo", "bar")).build();
AwsIamAuthentication sut = new AwsIamAuthentication(options, this.restTemplate);
VaultToken login = sut.login();
@@ -90,7 +91,7 @@ class AwsIamAuthenticationUnitTests {
+ "}"));
AwsIamAuthenticationOptions options = AwsIamAuthenticationOptions.builder().role("foo-role")
.credentials(new BasicAWSCredentials("foo", "bar")).build();
.credentials(AwsBasicCredentials.create("foo", "bar")).build();
AuthenticationSteps steps = AwsIamAuthentication.createAuthenticationSteps(options);
AuthenticationStepsExecutor executor = new AuthenticationStepsExecutor(steps, this.restTemplate);

View File

@@ -63,7 +63,7 @@
<netty.version>4.1.72.Final</netty.version>
<okhttp3.version>3.14.9</okhttp3.version>
<jackson-databind.version>2.13.3</jackson-databind.version>
<aws-java-sdk.version>1.11.975</aws-java-sdk.version>
<aws-java-sdk.version>2.17.152</aws-java-sdk.version>
<google-api-services-iam.version>v1-rev20210226-1.31.0</google-api-services-iam.version>
<google-cloud-iamcredentials.version>1.2.2</google-cloud-iamcredentials.version>
<google-auth-library-oauth2-http.version>0.22.2</google-auth-library-oauth2-http.version>
@@ -131,8 +131,8 @@
<!-- AWS SDK -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<groupId>software.amazon.awssdk</groupId>
<artifactId>auth</artifactId>
<version>${aws-java-sdk.version}</version>
<optional>true</optional>
</dependency>