diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java
index 6cb595e0b589..d7740f722770 100644
--- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java
+++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java
@@ -31,6 +31,7 @@
import software.amazon.awssdk.core.RequestOverrideConfiguration;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.SdkResponse;
+import software.amazon.awssdk.core.SelectedAuthScheme;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
import software.amazon.awssdk.core.client.config.SdkClientOption;
@@ -45,6 +46,7 @@
import software.amazon.awssdk.core.internal.util.HttpChecksumResolver;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.endpoints.EndpointProvider;
+import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme;
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeProvider;
import software.amazon.awssdk.identity.spi.IdentityProviders;
@@ -152,10 +154,28 @@ private AwsExecutionContextBuilder() {
/**
* We will load the old (non-SRA) signer if this client seems like an old version or the customer has provided a signer
* override. We assume that if there's no auth schemes defined, we're on the old code path.
+ *
+ * In addition, if authType=none, we don't need to use the old signer, even if overridden.
*/
private static boolean loadOldSigner(ExecutionAttributes attributes, SdkRequest request) {
- return attributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES) == null ||
- SignerOverrideUtils.isSignerOverridden(request, attributes);
+ Map> authSchemes = attributes.getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES);
+ if (authSchemes == null) {
+ // pre SRA case.
+ // We used to set IS_NONE_AUTH_TYPE_REQUEST = false when authType=none. Yes, false.
+ return attributes.getOptionalAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST).orElse(true);
+ }
+
+ // post SRA case.
+ // By default, SRA uses new HttpSigner, so we shouldn't use old non-SRA Signer, unless the customer has provided a signer
+ // override.
+ // But, if the operation was modeled as authTpye=None, we don't want to use the provided overridden Signer either. In
+ // post SRA, modeled authType=None would default to NoAuthAuthScheme.
+ // Note, for authType=None operation, technically, customer could override the AuthSchemeProvider and select a different
+ // AuthScheme (than NoAuthAuthScheme). In this case, we are choosing to use the customer's overridden Signer.
+ SelectedAuthScheme> selectedAuthScheme = attributes.getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
+ return SignerOverrideUtils.isSignerOverridden(request, attributes) &&
+ selectedAuthScheme != null &&
+ !NoAuthAuthScheme.SCHEME_ID.equals(selectedAuthScheme.authSchemeOption().schemeId());
}
private static void putAuthSchemeResolutionAttributes(ExecutionAttributes executionAttributes,
diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java
index 3aee114c1b20..91a18bfc8477 100644
--- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java
+++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java
@@ -17,14 +17,16 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import org.junit.Before;
import org.junit.Test;
@@ -32,12 +34,12 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
-import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.SdkResponse;
+import software.amazon.awssdk.core.SelectedAuthScheme;
import software.amazon.awssdk.core.checksums.ChecksumSpecs;
import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
@@ -51,6 +53,11 @@
import software.amazon.awssdk.core.interceptor.trait.HttpChecksum;
import software.amazon.awssdk.core.internal.util.HttpChecksumUtils;
import software.amazon.awssdk.core.signer.Signer;
+import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme;
+import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme;
+import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
+import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
+import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
import software.amazon.awssdk.identity.spi.IdentityProvider;
import software.amazon.awssdk.identity.spi.IdentityProviders;
@@ -65,16 +72,25 @@ public class AwsExecutionContextBuilderTest {
@Mock
ExecutionInterceptor interceptor;
+ @Mock
+ IdentityProvider defaultCredentialsProvider;
+
@Mock
Signer defaultSigner;
@Mock
Signer clientOverrideSigner;
+ @Mock
+ Map> defaultAuthSchemes;
+
@Before
public void setUp() throws Exception {
when(sdkRequest.overrideConfiguration()).thenReturn(Optional.empty());
when(interceptor.modifyRequest(any(), any())).thenReturn(sdkRequest);
+ when(defaultCredentialsProvider.resolveIdentity()).thenAnswer(
+ invocationOnMock -> CompletableFuture.completedFuture(AwsCredentialsIdentity.create("ak", "sk")));
+
}
@Test
@@ -109,17 +125,45 @@ public void verifyCoreExecutionAttributesTakePrecedence() {
assertThat(executionContext.executionAttributes().getAttribute(SdkExecutionAttribute.SERVICE_NAME)).isEqualTo("DoNotOverrideService");
}
+ // pre SRA, AuthorizationStrategy would setup the signer and resolve identity.
@Test
- public void signing_ifNoOverrides_assignDefaultSigner() {
+ public void preSra_signing_ifNoOverrides_assignDefaultSigner_resolveIdentity() {
ExecutionContext executionContext =
AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
- testClientConfiguration().build());
+ preSraClientConfiguration().build());
assertThat(executionContext.signer()).isEqualTo(defaultSigner);
+ verify(defaultCredentialsProvider, times(1)).resolveIdentity();
}
+ // This is post SRA case. This is asserting that AuthorizationStrategy is not used.
@Test
- public void signing_ifClientOverride_assignClientOverrideSigner() {
+ public void postSra_ifNoOverrides_doesNotResolveIdentity_doesNotAssignSigner() {
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ testClientConfiguration().build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void preSra_signing_ifClientOverride_assignClientOverrideSigner_resolveIdentity() {
+ Optional overrideConfiguration = Optional.of(AwsRequestOverrideConfiguration.builder()
+ .signer(clientOverrideSigner)
+ .build());
+ when(sdkRequest.overrideConfiguration()).thenReturn(overrideConfiguration);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ preSraClientConfiguration().build());
+
+ assertThat(executionContext.signer()).isEqualTo(clientOverrideSigner);
+ verify(defaultCredentialsProvider, times(1)).resolveIdentity();
+ }
+
+ @Test
+ public void postSra_signing_ifClientOverride_assignClientOverrideSigner_resolveIdentity() {
Optional overrideConfiguration = Optional.of(AwsRequestOverrideConfiguration.builder()
.signer(clientOverrideSigner)
.build());
@@ -130,6 +174,102 @@ public void signing_ifClientOverride_assignClientOverrideSigner() {
testClientConfiguration().build());
assertThat(executionContext.signer()).isEqualTo(clientOverrideSigner);
+ verify(defaultCredentialsProvider, times(1)).resolveIdentity();
+ }
+
+ @Test
+ public void preSra_authTypeNone_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = preSraClientConfiguration();
+ clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES)
+ // yes, our code would put false instead of true
+ .putAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void postSra_authTypeNone_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = noAuthAuthSchemeClientConfiguration();
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void preSra_authTypeNone_signerClientOverride_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = preSraClientConfiguration();
+ clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES)
+ // yes, our code would put false instead of true
+ .putAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false);
+ clientConfig.option(SdkAdvancedClientOption.SIGNER, this.clientOverrideSigner)
+ .option(SdkClientOption.SIGNER_OVERRIDDEN, true);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void postSra_authTypeNone_signerClientOverride_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = noAuthAuthSchemeClientConfiguration();
+ clientConfig.option(SdkAdvancedClientOption.SIGNER, this.clientOverrideSigner)
+ .option(SdkClientOption.SIGNER_OVERRIDDEN, true);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void preSra_authTypeNone_signerRequestOverride_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = preSraClientConfiguration();
+ clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES)
+ // yes, our code would put false instead of true
+ .putAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST, false);
+
+ Optional overrideConfiguration = Optional.of(AwsRequestOverrideConfiguration.builder()
+ .signer(clientOverrideSigner)
+ .build());
+ when(sdkRequest.overrideConfiguration()).thenReturn(overrideConfiguration);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
+ }
+
+ @Test
+ public void postSra_authTypeNone_signerRequestOverride_doesNotAssignSigner_doesNotResolveIdentity() {
+ SdkClientConfiguration.Builder clientConfig = noAuthAuthSchemeClientConfiguration();
+
+ Optional overrideConfiguration = Optional.of(AwsRequestOverrideConfiguration.builder()
+ .signer(clientOverrideSigner)
+ .build());
+ when(sdkRequest.overrideConfiguration()).thenReturn(overrideConfiguration);
+
+ ExecutionContext executionContext =
+ AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(),
+ clientConfig.build());
+
+ assertThat(executionContext.signer()).isNull();
+ verify(defaultCredentialsProvider, times(0)).resolveIdentity();
}
@Test
@@ -255,11 +395,44 @@ private ClientExecutionParams clientExecutionParams() {
}
private SdkClientConfiguration.Builder testClientConfiguration() {
+ // In real SRA case, SelectedAuthScheme is setup as an executionAttribute by {Service}AuthSchemeInterceptor that is setup
+ // in EXECUTION_INTERCEPTORS. But, faking it here for unit test, by already setting SELECTED_AUTH_SCHEME into the
+ // executionAttributes.
+ SelectedAuthScheme> selectedAuthScheme = new SelectedAuthScheme<>(
+ CompletableFuture.completedFuture(AwsCredentialsIdentity.create("ak", "sk")),
+ mock(HttpSigner.class),
+ AuthSchemeOption.builder().schemeId(AwsV4AuthScheme.SCHEME_ID).build()
+ );
+ ExecutionAttributes executionAttributes =
+ ExecutionAttributes.builder()
+ .put(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme)
+ .build();
+
List interceptorList = Collections.singletonList(interceptor);
return SdkClientConfiguration.builder()
- .option(SdkClientOption.EXECUTION_INTERCEPTORS, new ArrayList<>())
.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptorList)
- .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, DefaultCredentialsProvider.create())
- .option(SdkAdvancedClientOption.SIGNER, this.defaultSigner);
+ .option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, defaultCredentialsProvider)
+ .option(SdkClientOption.AUTH_SCHEMES, defaultAuthSchemes)
+ .option(SdkClientOption.EXECUTION_ATTRIBUTES, executionAttributes);
+ }
+
+ private SdkClientConfiguration.Builder noAuthAuthSchemeClientConfiguration() {
+ SdkClientConfiguration.Builder clientConfig = testClientConfiguration();
+ SelectedAuthScheme> selectedNoAuthScheme = new SelectedAuthScheme<>(
+ CompletableFuture.completedFuture(AwsCredentialsIdentity.create("ak", "sk")),
+ mock(HttpSigner.class),
+ AuthSchemeOption.builder().schemeId(NoAuthAuthScheme.SCHEME_ID).build()
+ );
+ clientConfig.option(SdkClientOption.EXECUTION_ATTRIBUTES)
+ .putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedNoAuthScheme);
+ return clientConfig;
+ }
+
+ private SdkClientConfiguration.Builder preSraClientConfiguration() {
+ SdkClientConfiguration.Builder clientConfiguration = testClientConfiguration();
+ clientConfiguration.option(SdkClientOption.EXECUTION_ATTRIBUTES)
+ .putAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, null);
+ return clientConfiguration.option(SdkClientOption.AUTH_SCHEMES, null)
+ .option(SdkAdvancedClientOption.SIGNER, this.defaultSigner);
}
}
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStage.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStage.java
index 416bcea38d40..762ffc5ca3cc 100644
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStage.java
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStage.java
@@ -67,19 +67,27 @@ public AsyncSigningStage(HttpClientDependencies dependencies) {
@Override
public CompletableFuture execute(SdkHttpFullRequest request, RequestExecutionContext context)
throws Exception {
- SelectedAuthScheme> selectedAuthScheme =
- context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
- if (shouldDoSraSigning(context, selectedAuthScheme)) {
+
+ updateHttpRequestInInterceptorContext(request, context.executionContext());
+
+ // Whether pre / post SRA, if old Signer is setup in context, that's the one to use
+ if (context.signer() != null) {
+ return signRequest(request, context);
+ }
+ // else if AUTH_SCHEMES != null (implies SRA), use SelectedAuthScheme
+ if (context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES) != null) {
+ SelectedAuthScheme> selectedAuthScheme =
+ context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
log.debug(() -> String.format("Using SelectedAuthScheme: %s", selectedAuthScheme.authSchemeOption().schemeId()));
return sraSignRequest(request, context, selectedAuthScheme);
}
- return signRequest(request, context);
+ // else, this implies pre SRA client with authType=None, so don't need to do anything
+ return CompletableFuture.completedFuture(request);
}
private CompletableFuture sraSignRequest(SdkHttpFullRequest request,
RequestExecutionContext context,
SelectedAuthScheme selectedAuthScheme) {
- updateHttpRequestInInterceptorContext(request, context.executionContext());
adjustForClockSkew(context.executionAttributes());
CompletableFuture extends T> identityFuture = selectedAuthScheme.identity();
return identityFuture.thenCompose(identity -> {
@@ -183,15 +191,9 @@ private SdkHttpFullRequest.Builder toSdkHttpFullRequestBuilder(BaseSignedRequest
*/
private CompletableFuture signRequest(SdkHttpFullRequest request,
RequestExecutionContext context) {
- updateHttpRequestInInterceptorContext(request, context.executionContext());
-
Signer signer = context.signer();
MetricCollector metricCollector = context.attemptMetricCollector();
- if (!shouldSign(context.executionAttributes(), signer)) {
- return CompletableFuture.completedFuture(request);
- }
-
adjustForClockSkew(context.executionAttributes());
AsyncSigner asyncSigner = asAsyncSigner(signer, context);
@@ -216,22 +218,6 @@ private void updateHttpRequestInInterceptorContext(SdkHttpFullRequest request, E
executionContext.interceptorContext(executionContext.interceptorContext().copy(b -> b.httpRequest(request)));
}
- /**
- * We sign if it isn't auth=none. This attribute is no longer set in the SRA, so this exists only for old clients. In
- * addition to this, old clients only set this to false, never true. So, we have to treat null as true.
- */
- private boolean shouldSign(ExecutionAttributes attributes, Signer signer) {
- return signer != null &&
- !Boolean.FALSE.equals(attributes.getAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST));
- }
-
- /**
- * Returns true if we should use SRA signing logic.
- */
- private boolean shouldDoSraSigning(RequestExecutionContext context, SelectedAuthScheme> selectedAuthScheme) {
- return context.signer() == null && selectedAuthScheme != null;
- }
-
/**
* Returns the {@link Clock} used for signing that already accounts for clock skew when detected by the retryable stage.
*/
diff --git a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java
index 9bf94b1d78c8..9a99af93e7da 100644
--- a/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java
+++ b/core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java
@@ -67,19 +67,26 @@ public SigningStage(HttpClientDependencies dependencies) {
public SdkHttpFullRequest execute(SdkHttpFullRequest request, RequestExecutionContext context) throws Exception {
InterruptMonitor.checkInterrupted();
- SelectedAuthScheme> selectedAuthScheme =
- context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
- if (shouldDoSraSigning(context, selectedAuthScheme)) {
+ updateHttpRequestInInterceptorContext(request, context.executionContext());
+
+ // Whether pre / post SRA, if old Signer is setup in context, that's the one to use
+ if (context.signer() != null) {
+ return signRequest(request, context);
+ }
+ // else if AUTH_SCHEMES != null (implies SRA), use SelectedAuthScheme
+ if (context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.AUTH_SCHEMES) != null) {
+ SelectedAuthScheme> selectedAuthScheme =
+ context.executionAttributes().getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME);
log.debug(() -> String.format("Using SelectedAuthScheme: %s", selectedAuthScheme.authSchemeOption().schemeId()));
return sraSignRequest(request, context, selectedAuthScheme);
}
- return signRequest(request, context);
+ // else, this implies pre SRA client, with authType=None, so don't need to do anything
+ return request;
}
private SdkHttpFullRequest sraSignRequest(SdkHttpFullRequest request,
RequestExecutionContext context,
SelectedAuthScheme selectedAuthScheme) {
- updateHttpRequestInInterceptorContext(request, context.executionContext());
adjustForClockSkew(context.executionAttributes());
CompletableFuture extends T> identityFuture = selectedAuthScheme.identity();
T identity = CompletableFutureUtils.joinLikeSync(identityFuture);
@@ -128,15 +135,9 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) {
* Sign the request if the signer if provided and credentials are present.
*/
private SdkHttpFullRequest signRequest(SdkHttpFullRequest request, RequestExecutionContext context) {
- updateHttpRequestInInterceptorContext(request, context.executionContext());
-
Signer signer = context.signer();
MetricCollector metricCollector = context.attemptMetricCollector();
- if (!shouldSign(context.executionAttributes(), signer)) {
- return request;
- }
-
adjustForClockSkew(context.executionAttributes());
Pair measuredSign = MetricUtils.measureDuration(
@@ -168,22 +169,6 @@ private void updateHttpRequestInInterceptorContext(SdkHttpFullRequest request, E
executionContext.interceptorContext(executionContext.interceptorContext().copy(b -> b.httpRequest(request)));
}
- /**
- * We sign if it isn't auth=none. This attribute is no longer set in the SRA, so this exists only for old clients. In
- * addition to this, old clients only set this to false, never true. So, we have to treat null as true.
- */
- private boolean shouldSign(ExecutionAttributes attributes, Signer signer) {
- return signer != null &&
- !Boolean.FALSE.equals(attributes.getAttribute(SdkInternalExecutionAttribute.IS_NONE_AUTH_TYPE_REQUEST));
- }
-
- /**
- * Returns true if we should use SRA signing logic.
- */
- private boolean shouldDoSraSigning(RequestExecutionContext context, SelectedAuthScheme> selectedAuthScheme) {
- return context.signer() == null && selectedAuthScheme != null;
- }
-
/**
* Returns the {@link Clock} used for signing that already accounts for clock skew when detected by the retryable stage.
*/
diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStageTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStageTest.java
index babc64483ff8..ae9851abe1f9 100644
--- a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStageTest.java
+++ b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/AsyncSigningStageTest.java
@@ -31,6 +31,7 @@
import java.time.Clock;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import org.junit.Before;
import org.junit.Test;
@@ -48,6 +49,7 @@
import software.amazon.awssdk.core.http.ExecutionContext;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.InterceptorContext;
+import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
import software.amazon.awssdk.core.internal.http.HttpClientDependencies;
import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
import software.amazon.awssdk.core.signer.AsyncRequestBodySigner;
@@ -539,12 +541,15 @@ private RequestExecutionContext createContext(SelectedAuthScheme selec
// .httpRequest(request)
.build();
- ExecutionAttributes executionAttributes = ExecutionAttributes.builder()
- .put(SELECTED_AUTH_SCHEME, selectedAuthScheme)
- .build();
+ ExecutionAttributes.Builder executionAttributes = ExecutionAttributes.builder()
+ .put(SELECTED_AUTH_SCHEME, selectedAuthScheme);
+ if (selectedAuthScheme != null) {
+ // Doesn't matter that it is empty, just needs to non-null, which implies SRA path.
+ executionAttributes.put(SdkInternalExecutionAttribute.AUTH_SCHEMES, new HashMap<>());
+ }
ExecutionContext executionContext = ExecutionContext.builder()
- .executionAttributes(executionAttributes)
+ .executionAttributes(executionAttributes.build())
.interceptorContext(interceptorContext)
.signer(oldSigner)
.build();
diff --git a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStageTest.java b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStageTest.java
index f6396a79f23f..865535a6298d 100644
--- a/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStageTest.java
+++ b/core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStageTest.java
@@ -30,6 +30,7 @@
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
+import java.util.HashMap;
import java.util.concurrent.CompletableFuture;
import org.junit.Before;
import org.junit.Test;
@@ -45,6 +46,7 @@
import software.amazon.awssdk.core.http.ExecutionContext;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.InterceptorContext;
+import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
import software.amazon.awssdk.core.internal.http.HttpClientDependencies;
import software.amazon.awssdk.core.internal.http.RequestExecutionContext;
import software.amazon.awssdk.core.signer.Signer;
@@ -380,12 +382,15 @@ private RequestExecutionContext createContext(SelectedAuthScheme selec
// .httpRequest(request)
.build();
- ExecutionAttributes executionAttributes = ExecutionAttributes.builder()
- .put(SELECTED_AUTH_SCHEME, selectedAuthScheme)
- .build();
+ ExecutionAttributes.Builder executionAttributes = ExecutionAttributes.builder()
+ .put(SELECTED_AUTH_SCHEME, selectedAuthScheme);
+ if (selectedAuthScheme != null) {
+ // Doesn't matter that it is empty, just needs to non-null, which implies SRA path.
+ executionAttributes.put(SdkInternalExecutionAttribute.AUTH_SCHEMES, new HashMap<>());
+ }
ExecutionContext executionContext = ExecutionContext.builder()
- .executionAttributes(executionAttributes)
+ .executionAttributes(executionAttributes.build())
.interceptorContext(interceptorContext)
.signer(oldSigner)
.build();
diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java
index e914d348ad2e..f11901ef1fa6 100644
--- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java
+++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/NoneAuthTypeRequestTest.java
@@ -17,6 +17,10 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import io.reactivex.Flowable;
import java.io.IOException;
@@ -24,9 +28,8 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import org.mockito.Mockito;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
-import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
+import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.awscore.client.builder.AwsAsyncClientBuilder;
import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder;
import software.amazon.awssdk.awscore.client.builder.AwsSyncClientBuilder;
@@ -48,8 +51,10 @@
/**
* Verify that the "authtype" C2J trait for request type is honored for each requests.
*/
+// TODO(sra-identity-auth): Verify these tests pass for useSraAuht=true
public class NoneAuthTypeRequestTest {
+ private AwsCredentialsProvider credentialsProvider;
private SdkHttpClient httpClient;
private SdkAsyncHttpClient httpAsyncClient;
private ProtocolRestJsonClient jsonClient;
@@ -57,11 +62,14 @@ public class NoneAuthTypeRequestTest {
private ProtocolRestXmlClient xmlClient;
private ProtocolRestXmlAsyncClient xmlAsyncClient;
-
@Before
public void setup() throws IOException {
- httpClient = Mockito.mock(SdkHttpClient.class);
- httpAsyncClient = Mockito.mock(SdkAsyncHttpClient.class);
+ credentialsProvider = mock(AwsCredentialsProvider.class);
+ when(credentialsProvider.resolveIdentity()).thenAnswer(
+ invocationOnMock -> CompletableFuture.completedFuture(AwsBasicCredentials.create("123", "12344")));
+
+ httpClient = mock(SdkHttpClient.class);
+ httpAsyncClient = mock(SdkAsyncHttpClient.class);
jsonClient = initializeSync(ProtocolRestJsonClient.builder()).build();
jsonAsyncClient = initializeAsync(ProtocolRestJsonAsyncClient.builder()).build();
xmlClient = initializeSync(ProtocolRestXmlClient.builder()).build();
@@ -72,13 +80,13 @@ public void setup() throws IOException {
.putHeader("Content-Length", "0")
.build();
- ExecutableHttpRequest request = Mockito.mock(ExecutableHttpRequest.class);
+ ExecutableHttpRequest request = mock(ExecutableHttpRequest.class);
- Mockito.when(request.call()).thenReturn(HttpExecuteResponse.builder()
+ when(request.call()).thenReturn(HttpExecuteResponse.builder()
.response(successfulHttpResponse)
.build());
- Mockito.when(httpClient.prepareRequest(any())).thenReturn(request);
- Mockito.when(httpAsyncClient.execute(any())).thenAnswer(invocation -> {
+ when(httpClient.prepareRequest(any())).thenReturn(request);
+ when(httpAsyncClient.execute(any())).thenAnswer(invocation -> {
AsyncExecuteRequest asyncExecuteRequest = invocation.getArgument(0, AsyncExecuteRequest.class);
asyncExecuteRequest.responseHandler().onHeaders(successfulHttpResponse);
asyncExecuteRequest.responseHandler().onStream(Flowable.empty());
@@ -90,68 +98,76 @@ public void setup() throws IOException {
public void sync_json_authorization_is_absent_for_noneAuthType() {
jsonClient.operationWithNoneAuthType(o -> o.booleanMember(true));
assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isNotPresent();
+ verify(credentialsProvider, times(0)).resolveIdentity();
}
@Test
public void sync_json_authorization_is_present_for_defaultAuth() {
jsonClient.jsonValuesOperation();
assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isPresent();
+ verify(credentialsProvider, times(1)).resolveIdentity();
}
@Test
public void async_json_authorization_is_absent_for_noneAuthType() {
jsonAsyncClient.operationWithNoneAuthType(o -> o.booleanMember(true));
assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isNotPresent();
+ verify(credentialsProvider, times(0)).resolveIdentity();
}
@Test
public void async_json_authorization_is_present_for_defaultAuth() {
jsonAsyncClient.jsonValuesOperation();
assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isPresent();
+ verify(credentialsProvider, times(1)).resolveIdentity();
}
@Test
public void sync_xml_authorization_is_absent_for_noneAuthType() {
xmlClient.operationWithNoneAuthType(o -> o.booleanMember(true));
assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isNotPresent();
+ verify(credentialsProvider, times(0)).resolveIdentity();
}
@Test
public void sync_xml_authorization_is_present_for_defaultAuth() {
xmlClient.jsonValuesOperation(json -> json.jsonValueMember("one"));
assertThat(getSyncRequest().firstMatchingHeader("Authorization")).isPresent();
+ verify(credentialsProvider, times(1)).resolveIdentity();
}
@Test
public void async_xml_authorization_is_absent_for_noneAuthType() {
xmlAsyncClient.operationWithNoneAuthType(o -> o.booleanMember(true));
assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isNotPresent();
+ verify(credentialsProvider, times(0)).resolveIdentity();
}
@Test
public void async_xml_authorization_is_present_for_defaultAuth() {
xmlAsyncClient.jsonValuesOperation(json -> json.jsonValueMember("one"));
assertThat(getAsyncRequest().firstMatchingHeader("Authorization")).isPresent();
+ verify(credentialsProvider, times(1)).resolveIdentity();
}
private SdkHttpRequest getSyncRequest() {
ArgumentCaptor captor = ArgumentCaptor.forClass(HttpExecuteRequest.class);
- Mockito.verify(httpClient).prepareRequest(captor.capture());
+ verify(httpClient).prepareRequest(captor.capture());
return captor.getValue().httpRequest();
}
private SdkHttpRequest getAsyncRequest() {
ArgumentCaptor captor = ArgumentCaptor.forClass(AsyncExecuteRequest.class);
- Mockito.verify(httpAsyncClient).execute(captor.capture());
+ verify(httpAsyncClient).execute(captor.capture());
return captor.getValue().request();
}
private & AwsClientBuilder> T initializeSync(T syncClientBuilder) {
- return initialize(syncClientBuilder.httpClient(httpClient).credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("123", "12344"))));
+ return initialize(syncClientBuilder.httpClient(httpClient).credentialsProvider(credentialsProvider));
}
private & AwsClientBuilder> T initializeAsync(T asyncClientBuilder) {
- return initialize(asyncClientBuilder.httpClient(httpAsyncClient));
+ return initialize(asyncClientBuilder.httpClient(httpAsyncClient).credentialsProvider(credentialsProvider));
}
private > T initialize(T clientBuilder) {