Skip to content

Add a test that the selected auth scheme signing clock will not be overwritten #4389

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import static software.amazon.awssdk.core.metrics.CoreMetric.SIGNING_DURATION;

import java.nio.ByteBuffer;
import java.time.Clock;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -148,9 +149,9 @@ public void execute_selectedAuthScheme_doesSraSign() throws Exception {
verifyNoInteractions(oldSigner);
}


@Test
public void execute_selectedAuthSchemeAndTimeOffsetSet_doesSraSignAndAdjustTheSigningClock() throws Exception {
AsyncRequestBody asyncPayload = AsyncRequestBody.fromString("async request body");
// Set up a scheme with a signer property
SelectedAuthScheme<Identity> selectedAuthScheme = new SelectedAuthScheme<>(
CompletableFuture.completedFuture(identity),
Expand All @@ -159,17 +160,19 @@ public void execute_selectedAuthSchemeAndTimeOffsetSet_doesSraSignAndAdjustTheSi
.schemeId("my.auth#myAuth")
.putSignerProperty(SIGNER_PROPERTY, "value")
.build());
RequestExecutionContext context = createContext(selectedAuthScheme, (Signer) null);

// Setup the timeoffset to test that the clock is setup properly.
httpClientDependencies.updateTimeOffset(TEST_TIME_OFFSET);
RequestExecutionContext context = createContext(selectedAuthScheme, asyncPayload, null);

SdkHttpRequest signedRequest = ValidSdkObjects.sdkHttpFullRequest().build();
when(signer.sign(Mockito.<SignRequest<? extends Identity>>any()))
.thenReturn(SignedRequest.builder()
.request(signedRequest)
.build());
Publisher<ByteBuffer> signedPayload = AsyncRequestBody.fromString("signed async request body");
when(signer.signAsync(Mockito.<AsyncSignRequest<? extends Identity>>any()))
.thenReturn(
CompletableFuture.completedFuture(AsyncSignedRequest.builder()
.request(signedRequest)
.payload(signedPayload)
.build()));

// Setup the timeoffset to test that the clock is setup properly.
httpClientDependencies.updateTimeOffset(TEST_TIME_OFFSET);
SdkHttpFullRequest request = ValidSdkObjects.sdkHttpFullRequest().build();
SdkHttpFullRequest result = stage.execute(request, context).join();

Expand All @@ -178,8 +181,8 @@ public void execute_selectedAuthSchemeAndTimeOffsetSet_doesSraSignAndAdjustTheSi
assertThat(context.executionContext().interceptorContext().httpRequest()).isSameAs(result);

// assert that the input to the signer is as expected, including that signer properties are set
verify(signer).sign(signRequestCaptor.capture());
SignRequest<? extends Identity> signRequest = signRequestCaptor.getValue();
verify(signer).signAsync(asyncSignRequestCaptor.capture());
AsyncSignRequest<? extends Identity> signRequest = asyncSignRequestCaptor.getValue();
assertThat(signRequest.identity()).isSameAs(identity);
assertThat(signRequest.request()).isSameAs(request);
assertThat(signRequest.property(SIGNER_PROPERTY)).isEqualTo("value");
Expand All @@ -196,6 +199,58 @@ public void execute_selectedAuthSchemeAndTimeOffsetSet_doesSraSignAndAdjustTheSi
verifyNoInteractions(oldSigner);
}

@Test
public void execute_selectedAuthScheme_doesSraSignAndDoesNotOverrideAuthSchemeOptionClock() throws Exception {
AsyncRequestBody asyncPayload = AsyncRequestBody.fromString("async request body");
// Set up a scheme with a signer property and the signing clock set
Clock clock = SigningStageTest.testClock();
SelectedAuthScheme<Identity> selectedAuthScheme = new SelectedAuthScheme<>(
CompletableFuture.completedFuture(identity),
signer,
AuthSchemeOption.builder()
.schemeId("my.auth#myAuth")
.putSignerProperty(SIGNER_PROPERTY, "value")
// The auth scheme option includes the signing clock property
.putSignerProperty(HttpSigner.SIGNING_CLOCK, clock)
.build());

RequestExecutionContext context = createContext(selectedAuthScheme, asyncPayload, null);

SdkHttpRequest signedRequest = ValidSdkObjects.sdkHttpFullRequest().build();
when(signer.signAsync(Mockito.<AsyncSignRequest<? extends Identity>>any()))
.thenReturn(
CompletableFuture.completedFuture(AsyncSignedRequest.builder()
.request(signedRequest)
.build()));

SdkHttpFullRequest request = ValidSdkObjects.sdkHttpFullRequest().build();
SdkHttpFullRequest result = stage.execute(request, context).join();

assertThat(result).isSameAs(signedRequest);
// assert that interceptor context is updated with result
assertThat(context.executionContext().interceptorContext().httpRequest()).isSameAs(result);

// assert that the input to the signer is as expected, including that signer properties are set
verify(signer).signAsync(asyncSignRequestCaptor.capture());
AsyncSignRequest<? extends Identity> signRequest = asyncSignRequestCaptor.getValue();
assertThat(signRequest.identity()).isSameAs(identity);
assertThat(signRequest.request()).isSameAs(request);
assertThat(signRequest.property(SIGNER_PROPERTY)).isEqualTo("value");

// Assert that the time offset set was zero
assertThat(signRequest.property(HttpSigner.SIGNING_CLOCK)).isNotNull();
assertThat(signRequest.property(HttpSigner.SIGNING_CLOCK).instant())
.isCloseTo(Instant.now(), within(10, ChronoUnit.MILLIS));

// assert that the signing stage does not override the auth-option provided clock.
assertThat(signRequest.property(HttpSigner.SIGNING_CLOCK)).isSameAs(clock);

// assert that metrics are collected
verify(metricCollector).reportMetric(eq(SIGNING_DURATION), any());

verifyNoInteractions(oldSigner);
}

@Test
public void execute_selectedAuthScheme_asyncRequestBody_doesSraSignAsync() throws Exception {
AsyncRequestBody asyncPayload = AsyncRequestBody.fromString("async request body");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import static software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME;
import static software.amazon.awssdk.core.metrics.CoreMetric.SIGNING_DURATION;

import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.concurrent.CompletableFuture;
import org.junit.Before;
Expand Down Expand Up @@ -183,6 +185,51 @@ public void execute_selectedAuthSchemeAndTimeOffsetSet_doesSraSignAndAdjustTheSi
verifyNoInteractions(oldSigner);
}

@Test
public void execute_selectedAuthScheme_doesSraSignAndDoesNotOverrideAuthSchemeOptionClock() throws Exception {
// Set up a scheme with a signer property and the signing clock set
Clock clock = testClock();
SelectedAuthScheme<Identity> selectedAuthScheme = new SelectedAuthScheme<>(
CompletableFuture.completedFuture(identity),
signer,
AuthSchemeOption.builder()
.schemeId("my.auth#myAuth")
.putSignerProperty(SIGNER_PROPERTY, "value")
// The auth scheme option includes the signing clock property
.putSignerProperty(HttpSigner.SIGNING_CLOCK, clock)
.build());
RequestExecutionContext context = createContext(selectedAuthScheme);

SdkHttpRequest signedRequest = ValidSdkObjects.sdkHttpFullRequest().build();
when(signer.sign(Mockito.<SignRequest<? extends Identity>>any()))
.thenReturn(SignedRequest.builder()
.request(signedRequest)
.build());

SdkHttpFullRequest request = ValidSdkObjects.sdkHttpFullRequest().build();
SdkHttpFullRequest result = stage.execute(request, context);

assertThat(result).isSameAs(signedRequest);
// assert that interceptor context is updated with result
assertThat(context.executionContext().interceptorContext().httpRequest()).isSameAs(result);

// assert that the input to the signer is as expected, including that signer properties are set
verify(signer).sign(signRequestCaptor.capture());
SignRequest<? extends Identity> signRequest = signRequestCaptor.getValue();
assertThat(signRequest.identity()).isSameAs(identity);
assertThat(signRequest.request()).isSameAs(request);
assertThat(signRequest.property(SIGNER_PROPERTY)).isEqualTo("value");
assertThat(signRequest.property(HttpSigner.SIGNING_CLOCK)).isNotNull();

// assert that the signing stage does not override the auth-option provided clock.
assertThat(signRequest.property(HttpSigner.SIGNING_CLOCK)).isSameAs(clock);

// assert that metrics are collected
verify(metricCollector).reportMetric(eq(SIGNING_DURATION), any());

verifyNoInteractions(oldSigner);
}

@Test
public void execute_selectedNoAuthAuthScheme_doesSraSign() throws Exception {
// Set up a scheme with smithy.api#noAuth
Expand Down Expand Up @@ -395,4 +442,23 @@ private RequestExecutionContext createContext(SelectedAuthScheme<Identity> selec
context.attemptMetricCollector(metricCollector);
return context;
}

public static Clock testClock() {
return new Clock() {
@Override
public ZoneId getZone() {
throw new UnsupportedOperationException();
}

@Override
public Clock withZone(ZoneId zone) {
throw new UnsupportedOperationException();
}

@Override
public Instant instant() {
return Instant.now();
}
};
}
}