Skip to content

Commit e52ea62

Browse files
committed
Fixes after merge
1 parent 119cfbf commit e52ea62

File tree

12 files changed

+170
-92
lines changed

12 files changed

+170
-92
lines changed

.changes/next-release/feature-AWSSDKForJavav2-3b0176a.json

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "",
5+
"description": "Add support for payload signing of async streaming requests signed with SigV4 using default `AwsV4HttpSigner` (using `AwsV4HttpSigner.create()`). Note, requests using the `http` URI scheme will not be signed regardless of the value of `AwsV4FamilyHttpSigner.PAYLOAD_SIGNING_ENABLED` to remain consistent with existing behavior. This may change in a future release."
6+
}

core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSigner.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public SignedRequest sign(SignRequest<? extends AwsCredentialsIdentity> request)
6969

7070
@Override
7171
public CompletableFuture<AsyncSignedRequest> signAsync(AsyncSignRequest<? extends AwsCredentialsIdentity> request) {
72-
Checksummer checksummer = checksummer(request, null, checksumStore(request));
72+
Checksummer checksummer = asyncChecksummer(request, checksumStore(request));
7373
V4Properties v4Properties = v4Properties(request);
7474
V4RequestSigner v4RequestSigner = v4RequestSigner(request, v4Properties);
7575
V4PayloadSigner payloadSigner = v4PayloadAsyncSigner(request, v4Properties);
@@ -81,7 +81,7 @@ private static V4Properties v4Properties(BaseSignRequest<?, ? extends AwsCredent
8181
Clock signingClock = request.requireProperty(SIGNING_CLOCK, Clock.systemUTC());
8282
Instant signingInstant = signingClock.instant();
8383
AwsCredentialsIdentity credentials = sanitizeCredentials(request.identity());
84-
String regionName = request.requireProperty(AwsV4HttpSigner.REGION_NAME);
84+
String regionName = request.requireProperty(REGION_NAME);
8585
String serviceSigningName = request.requireProperty(SERVICE_SIGNING_NAME);
8686
CredentialScope credentialScope = new CredentialScope(regionName, serviceSigningName, signingInstant);
8787
boolean doubleUrlEncode = request.requireProperty(DOUBLE_URL_ENCODE, true);
@@ -129,9 +129,29 @@ private static V4RequestSigner v4RequestSigner(
129129
return requestSigner.apply(v4Properties);
130130
}
131131

132+
// TODO: remove this once we consolidate the behavior for plaintext HTTP signing for sync and async
133+
private static Checksummer asyncChecksummer(BaseSignRequest<?, ? extends AwsCredentialsIdentity> request,
134+
PayloadChecksumStore checksumStore) {
135+
boolean shouldTreatAsUnsigned = asyncShouldTreatAsUnsigned(request);
136+
137+
// set the override to false if it should be treated as unsigned, otherwise, null should be passed so that the normal
138+
// check for payload signing is done.
139+
Boolean overridePayloadSigning = shouldTreatAsUnsigned ? false : null;
140+
141+
return checksummer(request, overridePayloadSigning, checksumStore);
142+
}
143+
144+
// TODO: remove this once we consolidate the behavior for plaintext HTTP signing for sync and async
145+
private static boolean asyncShouldTreatAsUnsigned(BaseSignRequest<?, ? extends AwsCredentialsIdentity> request) {
146+
boolean isHttp = !"https".equals(request.request().protocol());
147+
boolean isPayloadSigning = isPayloadSigning(request);
148+
boolean isChunkEncoding = request.requireProperty(CHUNK_ENCODING_ENABLED, false);
149+
150+
return isHttp && isPayloadSigning && isChunkEncoding;
151+
}
152+
132153
private static V4PayloadSigner v4PayloadSigner(
133-
SignRequest<? extends AwsCredentialsIdentity> request,
134-
V4Properties properties) {
154+
BaseSignRequest<?, ? extends AwsCredentialsIdentity> request, V4Properties properties) {
135155

136156
boolean isPayloadSigning = isPayloadSigning(request);
137157
boolean isEventStreaming = isEventStreaming(request.request());
@@ -162,6 +182,7 @@ private static V4PayloadSigner v4PayloadSigner(
162182
return V4PayloadSigner.create();
163183
}
164184

185+
// TODO: remove this once we consolidate the behavior for plaintext HTTP signing for sync and async
165186
private static V4PayloadSigner v4PayloadAsyncSigner(
166187
AsyncSignRequest<? extends AwsCredentialsIdentity> request,
167188
V4Properties properties) {
@@ -183,10 +204,19 @@ private static V4PayloadSigner v4PayloadAsyncSigner(
183204
throw new UnsupportedOperationException("Unsigned payload is not supported with event-streaming.");
184205
}
185206

186-
if (useChunkEncoding(isPayloadSigning, isChunkEncoding, isTrailing || isFlexible)) {
207+
// Note: this check is done after we check if the request is eventstreaming, during which we just use the same logic
208+
// as sync to determine if the body should be signed. If it's not eventstreaming, then async needs to treat this
209+
// request differently to maintain current behavior re: plain HTTP requests.
210+
boolean nonEvenstreamingPayloadSigning = isPayloadSigning;
211+
if (asyncShouldTreatAsUnsigned(request)) {
212+
nonEvenstreamingPayloadSigning = false;
213+
}
214+
215+
if (useChunkEncoding(nonEvenstreamingPayloadSigning, isChunkEncoding, isTrailing || isFlexible)) {
187216
return AwsChunkedV4PayloadSigner.builder()
188217
.credentialScope(properties.getCredentialScope())
189218
.chunkSize(DEFAULT_CHUNK_SIZE_IN_BYTES)
219+
.checksumStore(checksumStore(request))
190220
.checksumAlgorithm(request.property(CHECKSUM_ALGORITHM))
191221
.build();
192222
}

core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/TestUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner.SERVICE_SIGNING_NAME;
55
import static software.amazon.awssdk.http.auth.spi.signer.HttpSigner.SIGNING_CLOCK;
66

7+
import io.reactivex.Flowable;
78
import java.io.ByteArrayInputStream;
89
import java.net.URI;
910
import java.nio.ByteBuffer;
@@ -13,6 +14,7 @@
1314
import java.time.ZoneId;
1415
import java.time.ZoneOffset;
1516
import java.util.function.Consumer;
17+
import org.reactivestreams.Publisher;
1618
import software.amazon.awssdk.http.SdkHttpMethod;
1719
import software.amazon.awssdk.http.SdkHttpRequest;
1820
import software.amazon.awssdk.http.auth.spi.signer.AsyncSignRequest;
@@ -58,10 +60,8 @@ public static <T extends AwsCredentialsIdentity> AsyncSignRequest<T> generateBas
5860
Consumer<? super SdkHttpRequest.Builder> requestOverrides,
5961
Consumer<? super AsyncSignRequest.Builder<T>> signRequestOverrides
6062
) {
61-
SimplePublisher<ByteBuffer> publisher = new SimplePublisher<>();
6263

63-
publisher.send(ByteBuffer.wrap(testPayload()));
64-
publisher.complete();
64+
Publisher<ByteBuffer> publisher = Flowable.just(ByteBuffer.wrap(testPayload()));
6565

6666
return AsyncSignRequest.builder(credentials)
6767
.request(SdkHttpRequest.builder()

core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,21 @@
3030
import static software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner.PAYLOAD_SIGNING_ENABLED;
3131
import static software.amazon.awssdk.http.auth.spi.signer.SdkInternalHttpSignerProperty.CHECKSUM_STORE;
3232

33+
import io.reactivex.Flowable;
3334
import java.io.IOException;
3435
import java.net.URI;
36+
import java.nio.ByteBuffer;
3537
import java.nio.charset.StandardCharsets;
3638
import java.time.Duration;
37-
import java.util.Optional;
39+
import java.util.List;
40+
import java.util.stream.Collectors;
3841
import org.junit.jupiter.api.Disabled;
3942
import org.junit.jupiter.api.Test;
4043
import org.junit.jupiter.params.ParameterizedTest;
4144
import org.junit.jupiter.params.provider.ValueSource;
4245
import org.mockito.MockedStatic;
4346
import org.mockito.Mockito;
47+
import org.reactivestreams.Publisher;
4448
import software.amazon.awssdk.checksums.SdkChecksum;
4549
import software.amazon.awssdk.checksums.spi.ChecksumAlgorithm;
4650
import software.amazon.awssdk.http.Header;
@@ -709,7 +713,9 @@ void sign_WithPayloadSigningTrueAndChunkEncodingTrueAndHttp_SignsPayload() {
709713
}
710714

711715
@Test
712-
void signAsync_WithPayloadSigningTrueAndChunkEncodingTrueAndHttp_IgnoresPayloadSigning() {
716+
@Disabled("Fallback to signing is disabled to match pre-SRA behavior")
717+
// TODO: Enable this test once we figure out what the expected behavior is post SRA. See JAVA-8078
718+
void signAsync_WithPayloadSigningTrueAndChunkEncodingTrueAndHttp_RespectsPayloadSigning() {
713719
AsyncSignRequest<? extends AwsCredentialsIdentity> request = generateBasicAsyncRequest(
714720
AwsCredentialsIdentity.create("access", "secret"),
715721
httpRequest -> httpRequest.uri(URI.create("http://demo.us-east-1.amazonaws.com")),
@@ -727,6 +733,8 @@ void signAsync_WithPayloadSigningTrueAndChunkEncodingTrueAndHttp_IgnoresPayloadS
727733
}
728734

729735
@Test
736+
@Disabled("Fallback to signing is disabled to match pre-SRA behavior")
737+
// TODO: Enable this test once we figure out what the expected behavior is post SRA. See JAVA-8078
730738
void sign_WithPayloadSigningFalseAndChunkEncodingTrueAndHttp_SignsPayload() {
731739
SignRequest<? extends AwsCredentialsIdentity> request = generateBasicRequest(
732740
AwsCredentialsIdentity.create("access", "secret"),
@@ -745,7 +753,9 @@ void sign_WithPayloadSigningFalseAndChunkEncodingTrueAndHttp_SignsPayload() {
745753
}
746754

747755
@Test
748-
void signAsync_WithPayloadSigningFalseAndChunkEncodingTrueAndHttp_DoesNotFallBackToPayloadSigning() {
756+
@Disabled("Fallback to signing is disabled to match pre-SRA behavior")
757+
// TODO: Enable this test once we figure out what the expected behavior is post SRA. See JAVA-8078
758+
void signAsync_WithPayloadSigningFalseAndChunkEncodingTrueAndHttp_FallsBackToPayloadSigning() {
749759
AsyncSignRequest<? extends AwsCredentialsIdentity> request = generateBasicAsyncRequest(
750760
AwsCredentialsIdentity.create("access", "secret"),
751761
httpRequest -> httpRequest.uri(URI.create("http://demo.us-east-1.amazonaws.com")),
@@ -783,7 +793,9 @@ void sign_WithPayloadSigningFalseAndChunkEncodingTrueAndFlexibleChecksumAndHttp_
783793
}
784794

785795
@Test
786-
void signAsync_WithPayloadSigningFalseAndChunkEncodingTrueAndFlexibleChecksumAndHttp_DoesNotFallBackToPayloadSigning() {
796+
@Disabled("Fallback to signing is disabled to match pre-SRA behavior")
797+
// TODO: Enable this test once we figure out what the expected behavior is post SRA. See JAVA-8078
798+
void signAsync_WithPayloadSigningFalseAndChunkEncodingTrueAndFlexibleChecksumAndHttp_FallsBackToPayloadSigning() {
787799
AsyncSignRequest<? extends AwsCredentialsIdentity> request = generateBasicAsyncRequest(
788800
AwsCredentialsIdentity.create("access", "secret"),
789801
httpRequest -> httpRequest.uri(URI.create("http://demo.us-east-1.amazonaws.com")),
@@ -900,9 +912,61 @@ void sign_withPayloadSigningTrue_chunkEncodingFalse_withChecksum_cacheEmpty_stor
900912
assertThat(cache.getChecksumValue(CRC32)).isEqualTo(crc32Value);
901913
}
902914

915+
@Test
916+
void signAsync_WithPayloadSigningFalse_chunkEncodingTrue_cacheEmpty_storesComputedChecksum() throws IOException {
917+
PayloadChecksumStore cache = PayloadChecksumStore.create();
918+
919+
AsyncSignRequest<? extends AwsCredentialsIdentity> request = generateBasicAsyncRequest(
920+
AwsCredentialsIdentity.create("access", "secret"),
921+
httpRequest -> httpRequest.uri(URI.create("http://demo.us-east-1.amazonaws.com")),
922+
signRequest -> signRequest
923+
.putProperty(PAYLOAD_SIGNING_ENABLED, false)
924+
.putProperty(CHUNK_ENCODING_ENABLED, true)
925+
.putProperty(CHECKSUM_ALGORITHM, CRC32)
926+
.putProperty(CHECKSUM_STORE, cache)
927+
);
928+
929+
AsyncSignedRequest signedRequest = signer.signAsync(request).join();
930+
931+
getAllItems(signedRequest.payload().get());
932+
assertThat(cache.getChecksumValue(CRC32)).isEqualTo(computeChecksum(CRC32, testPayload()));
933+
}
934+
935+
@Test
936+
void signAsync_WithPayloadSigningFalse_chunkEncodingTrue_cacheContainsChecksum_usesCachedValue() throws IOException {
937+
PayloadChecksumStore cache = PayloadChecksumStore.create();
938+
939+
byte[] checksumValue = "my-checksum".getBytes(StandardCharsets.UTF_8);
940+
cache.putChecksumValue(CRC32, checksumValue);
941+
942+
AsyncSignRequest<? extends AwsCredentialsIdentity> request = generateBasicAsyncRequest(
943+
AwsCredentialsIdentity.create("access", "secret"),
944+
httpRequest -> httpRequest.uri(URI.create("http://demo.us-east-1.amazonaws.com")),
945+
signRequest -> signRequest
946+
.putProperty(PAYLOAD_SIGNING_ENABLED, false)
947+
.putProperty(CHUNK_ENCODING_ENABLED, true)
948+
.putProperty(CHECKSUM_ALGORITHM, CRC32)
949+
.putProperty(CHECKSUM_STORE, cache)
950+
);
951+
952+
AsyncSignedRequest signedRequest = signer.signAsync(request).join();
953+
954+
List<ByteBuffer> content = getAllItems(signedRequest.payload().get());
955+
String contentAsString = content.stream().map(DefaultAwsV4HttpSignerTest::bufferAsString).collect(Collectors.joining());
956+
assertThat(contentAsString).contains("x-amz-checksum-crc32:" + BinaryUtils.toBase64(checksumValue) + "\r\n");
957+
}
958+
903959
private static byte[] computeChecksum(ChecksumAlgorithm algorithm, byte[] data) {
904960
SdkChecksum checksum = SdkChecksum.forAlgorithm(algorithm);
905961
checksum.update(data, 0, data.length);
906962
return checksum.getChecksumBytes();
907963
}
964+
965+
private List<ByteBuffer> getAllItems(Publisher<ByteBuffer> publisher) {
966+
return Flowable.fromPublisher(publisher).toList().blockingGet();
967+
}
968+
969+
private static String bufferAsString(ByteBuffer buffer) {
970+
return StandardCharsets.UTF_8.decode(buffer.duplicate()).toString();
971+
}
908972
}

0 commit comments

Comments
 (0)