Upgrade to AWS SDK v2.
Original pull request: gh-693. Closes gh-253
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user