Skip to content

Commit d206a72

Browse files
authored
Fixed an issue where request-level signer overridden from execution interceptor is not honored (#5420)
1 parent 8e7d6f0 commit d206a72

File tree

5 files changed

+172
-70
lines changed

5 files changed

+172
-70
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "bugfix",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Fixed the issue where request-level signer override provided through ExecutionInterceptor is not honored."
6+
}

core/aws-core/src/main/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,11 @@ private AwsExecutionContextBuilder() {
131131
.build();
132132
interceptorContext = runInitialInterceptors(interceptorContext, executionAttributes, executionInterceptorChain);
133133

134+
SdkRequest modifiedRequests = interceptorContext.request();
134135
Signer signer = null;
135-
if (loadOldSigner(executionAttributes, originalRequest)) {
136+
if (loadOldSigner(executionAttributes, modifiedRequests)) {
136137
AuthorizationStrategyFactory authorizationStrategyFactory =
137-
new AuthorizationStrategyFactory(interceptorContext.request(), metricCollector, clientConfig);
138+
new AuthorizationStrategyFactory(modifiedRequests, metricCollector, clientConfig);
138139
AuthorizationStrategy authorizationStrategy =
139140
authorizationStrategyFactory.strategyFor(executionParams.credentialType());
140141
authorizationStrategy.addCredentialsToExecutionAttributes(executionAttributes);

core/aws-core/src/test/java/software/amazon/awssdk/awscore/internal/AwsExecutionContextBuilderTest.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import static org.mockito.Mockito.verify;
2323
import static org.mockito.Mockito.when;
2424

25+
import java.util.Arrays;
2526
import java.util.Collections;
2627
import java.util.List;
2728
import java.util.Map;
@@ -35,8 +36,10 @@
3536
import org.mockito.junit.MockitoJUnitRunner;
3637
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
3738
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
39+
import software.amazon.awssdk.awscore.AwsRequest;
3840
import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
3941
import software.amazon.awssdk.awscore.client.config.AwsClientOption;
42+
import software.amazon.awssdk.awscore.client.http.NoopTestAwsRequest;
4043
import software.amazon.awssdk.core.SdkRequest;
4144
import software.amazon.awssdk.core.SdkResponse;
4245
import software.amazon.awssdk.core.SelectedAuthScheme;
@@ -46,22 +49,26 @@
4649
import software.amazon.awssdk.core.client.config.SdkClientOption;
4750
import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
4851
import software.amazon.awssdk.core.http.ExecutionContext;
52+
import software.amazon.awssdk.core.interceptor.Context;
4953
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
5054
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
5155
import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
5256
import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
5357
import software.amazon.awssdk.core.interceptor.trait.HttpChecksum;
5458
import software.amazon.awssdk.core.internal.util.HttpChecksumUtils;
59+
import software.amazon.awssdk.core.signer.NoOpSigner;
5560
import software.amazon.awssdk.core.signer.Signer;
5661
import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme;
5762
import software.amazon.awssdk.http.auth.scheme.NoAuthAuthScheme;
5863
import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme;
5964
import software.amazon.awssdk.http.auth.spi.scheme.AuthSchemeOption;
6065
import software.amazon.awssdk.http.auth.spi.signer.HttpSigner;
66+
import software.amazon.awssdk.http.auth.spi.signer.SignerProperty;
6167
import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
6268
import software.amazon.awssdk.identity.spi.IdentityProvider;
6369
import software.amazon.awssdk.identity.spi.IdentityProviders;
6470
import software.amazon.awssdk.profiles.ProfileFile;
71+
import software.amazon.awssdk.regions.RegionScope;
6572

6673
@RunWith(MockitoJUnitRunner.class)
6774
public class AwsExecutionContextBuilderTest {
@@ -177,6 +184,34 @@ public void postSra_signing_ifClientOverride_assignClientOverrideSigner_resolveI
177184
verify(defaultCredentialsProvider, times(1)).resolveIdentity();
178185
}
179186

187+
@Test
188+
public void postSra_oldSignerOverriddenThroughExecutionInterceptor_shouldTakePrecedence() {
189+
SdkRequest request = NoopTestAwsRequest.builder().build();
190+
191+
Signer noOpSigner = new NoOpSigner();
192+
ExecutionInterceptor signerExecutionInterceptor = signerOverrideExecutionInterceptor(noOpSigner);
193+
SdkClientConfiguration configuration = testClientConfiguration(signerExecutionInterceptor).build();
194+
ExecutionContext executionContext =
195+
AwsExecutionContextBuilder.invokeInterceptorsAndCreateExecutionContext(clientExecutionParams(request),
196+
configuration);
197+
198+
assertThat(executionContext.signer()).isEqualTo(noOpSigner);
199+
verify(defaultCredentialsProvider, times(1)).resolveIdentity();
200+
}
201+
202+
private ExecutionInterceptor signerOverrideExecutionInterceptor(Signer signer) {
203+
return new ExecutionInterceptor() {
204+
@Override
205+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
206+
AwsRequest.Builder builder = (AwsRequest.Builder) context.request().toBuilder();
207+
builder.overrideConfiguration(c -> c.signer(signer)
208+
.build());
209+
210+
return builder.build();
211+
}
212+
};
213+
}
214+
180215
@Test
181216
public void preSra_authTypeNone_doesNotAssignSigner_doesNotResolveIdentity() {
182217
SdkClientConfiguration.Builder clientConfig = preSraClientConfiguration();
@@ -388,13 +423,21 @@ public void invokeInterceptorsAndCreateExecutionContext_requestOverrideForIdenti
388423
}
389424

390425
private ClientExecutionParams<SdkRequest, SdkResponse> clientExecutionParams() {
426+
return clientExecutionParams(sdkRequest);
427+
}
428+
429+
private ClientExecutionParams<SdkRequest, SdkResponse> clientExecutionParams(SdkRequest sdkRequest) {
391430
return new ClientExecutionParams<SdkRequest, SdkResponse>()
392431
.withInput(sdkRequest)
393432
.withFullDuplex(false)
394433
.withOperationName("TestOperation");
395434
}
396435

397436
private SdkClientConfiguration.Builder testClientConfiguration() {
437+
return testClientConfiguration(interceptor);
438+
}
439+
440+
private SdkClientConfiguration.Builder testClientConfiguration(ExecutionInterceptor... executionInterceptors) {
398441
// In real SRA case, SelectedAuthScheme is setup as an executionAttribute by {Service}AuthSchemeInterceptor that is setup
399442
// in EXECUTION_INTERCEPTORS. But, faking it here for unit test, by already setting SELECTED_AUTH_SCHEME into the
400443
// executionAttributes.
@@ -408,9 +451,8 @@ private SdkClientConfiguration.Builder testClientConfiguration() {
408451
.put(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME, selectedAuthScheme)
409452
.build();
410453

411-
List<ExecutionInterceptor> interceptorList = Collections.singletonList(interceptor);
412454
return SdkClientConfiguration.builder()
413-
.option(SdkClientOption.EXECUTION_INTERCEPTORS, interceptorList)
455+
.option(SdkClientOption.EXECUTION_INTERCEPTORS, Arrays.asList(executionInterceptors))
414456
.option(AwsClientOption.CREDENTIALS_IDENTITY_PROVIDER, defaultCredentialsProvider)
415457
.option(SdkClientOption.AUTH_SCHEMES, defaultAuthSchemes)
416458
.option(SdkClientOption.EXECUTION_ATTRIBUTES, executionAttributes);

test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/AsyncSignerOverrideTest.java

Lines changed: 0 additions & 66 deletions
This file was deleted.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
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.services;
17+
18+
import static org.mockito.ArgumentMatchers.any;
19+
import static org.mockito.Mockito.verify;
20+
import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.SIGNER;
21+
22+
import java.net.URI;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.mockito.Mock;
26+
import org.mockito.junit.MockitoJUnitRunner;
27+
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
28+
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
29+
import software.amazon.awssdk.awscore.AwsRequest;
30+
import software.amazon.awssdk.core.SdkRequest;
31+
import software.amazon.awssdk.core.async.AsyncRequestBody;
32+
import software.amazon.awssdk.core.interceptor.Context;
33+
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
34+
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
35+
import software.amazon.awssdk.core.signer.Signer;
36+
import software.amazon.awssdk.http.SdkHttpFullRequest;
37+
import software.amazon.awssdk.regions.Region;
38+
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonAsyncClient;
39+
import software.amazon.awssdk.services.protocolrestjson.ProtocolRestJsonClient;
40+
import software.amazon.awssdk.services.protocolrestjson.model.AllTypesRequest;
41+
import software.amazon.awssdk.services.protocolrestjson.model.StreamingInputOperationRequest;
42+
43+
44+
@RunWith(MockitoJUnitRunner.class)
45+
public class SignerOverrideTest {
46+
@Mock
47+
public Signer mockSigner;
48+
49+
/**
50+
* Test to ensure that operations that use the {@link software.amazon.awssdk.auth.signer.AsyncAws4Signer} don't apply
51+
* the override when the signer is overridden by the customer.
52+
*/
53+
@Test
54+
public void test_signerOverriddenForStreamingInput_takesPrecedence() {
55+
ProtocolRestJsonAsyncClient asyncClient = ProtocolRestJsonAsyncClient.builder()
56+
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")))
57+
.region(Region.US_WEST_2)
58+
.overrideConfiguration(o -> o.putAdvancedOption(SIGNER, mockSigner))
59+
.build();
60+
61+
try {
62+
asyncClient.streamingInputOperation(StreamingInputOperationRequest.builder().build(),
63+
AsyncRequestBody.fromString("test")).join();
64+
} catch (Exception expected) {
65+
}
66+
67+
verify(mockSigner).sign(any(SdkHttpFullRequest.class), any(ExecutionAttributes.class));
68+
}
69+
70+
@Test
71+
public void asyncClient_oldSignerOverriddenInExecutionInterceptor_takesPrecedence() {
72+
try (ProtocolRestJsonAsyncClient asyncClient = ProtocolRestJsonAsyncClient.builder()
73+
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")))
74+
.region(Region.US_WEST_2)
75+
.endpointOverride(URI.create("http://localhost:8080"))
76+
.overrideConfiguration(o -> o.addExecutionInterceptor(signerOverrideExecutionInterceptor(mockSigner)))
77+
.build()) {
78+
asyncClient.allTypes(AllTypesRequest.builder().build()).join();
79+
} catch (Exception expected) {
80+
// Doesn't matter if the request succeeds or not
81+
}
82+
83+
verify(mockSigner).sign(any(SdkHttpFullRequest.class), any(ExecutionAttributes.class));
84+
}
85+
86+
@Test
87+
public void syncClient_oldSignerOverriddenInExecutionInterceptor_takesPrecedence() {
88+
try (ProtocolRestJsonClient client = ProtocolRestJsonClient.builder()
89+
.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")))
90+
.region(Region.US_WEST_2)
91+
.endpointOverride(URI.create("http://localhost:8080"))
92+
.overrideConfiguration(o -> o.addExecutionInterceptor(signerOverrideExecutionInterceptor(mockSigner)))
93+
.build()) {
94+
client.allTypes(AllTypesRequest.builder().build());
95+
} catch (Exception expected) {
96+
// Doesn't matter if the request succeeds or not
97+
}
98+
99+
verify(mockSigner).sign(any(SdkHttpFullRequest.class), any(ExecutionAttributes.class));
100+
}
101+
102+
private ExecutionInterceptor signerOverrideExecutionInterceptor(Signer signer) {
103+
return new ExecutionInterceptor() {
104+
@Override
105+
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
106+
AwsRequest.Builder builder = (AwsRequest.Builder) context.request().toBuilder();
107+
builder.overrideConfiguration(c -> c.signer(signer)
108+
.build());
109+
110+
return builder.build();
111+
}
112+
};
113+
}
114+
115+
// TODO(sra-identity-and-auth): Add test for SRA way of overriding signer to assert that overridden signer is used.
116+
// At that point, rename this class to SignerOverrideTest, not specific to AsyncSignerOverride (which was for operation
117+
// level codegen changes).
118+
119+
}

0 commit comments

Comments
 (0)