|
17 | 17 |
|
18 | 18 |
|
19 | 19 | import static org.assertj.core.api.Assertions.assertThat;
|
| 20 | +import static org.assertj.core.api.Java6Assertions.assertThatThrownBy; |
20 | 21 | import static software.amazon.awssdk.core.ClientType.SYNC;
|
21 | 22 | import static software.amazon.awssdk.core.interceptor.SdkExecutionAttribute.CLIENT_TYPE;
|
22 | 23 | import static software.amazon.awssdk.core.interceptor.SdkExecutionAttribute.SERVICE_CONFIG;
|
23 | 24 | import static software.amazon.awssdk.services.s3.checksums.ChecksumConstant.CHECKSUM_ENABLED_RESPONSE_HEADER;
|
24 | 25 | import static software.amazon.awssdk.services.s3.checksums.ChecksumConstant.CONTENT_LENGTH_HEADER;
|
25 | 26 | import static software.amazon.awssdk.services.s3.checksums.ChecksumConstant.ENABLE_MD5_CHECKSUM_HEADER_VALUE;
|
| 27 | +import static software.amazon.awssdk.services.s3.checksums.ChecksumConstant.SERVER_SIDE_ENCRYPTION_HEADER; |
26 | 28 | import static software.amazon.awssdk.services.s3.checksums.ChecksumsEnabledValidator.CHECKSUM;
|
| 29 | +import static software.amazon.awssdk.services.s3.model.ServerSideEncryption.AWS_KMS; |
27 | 30 |
|
28 | 31 | import java.io.IOException;
|
29 | 32 | import java.io.InputStream;
|
| 33 | +import java.net.URI; |
30 | 34 | import java.nio.ByteBuffer;
|
| 35 | +import java.nio.charset.Charset; |
31 | 36 | import java.util.ArrayList;
|
32 | 37 | import java.util.List;
|
33 | 38 | import java.util.Optional;
|
|
38 | 43 | import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
|
39 | 44 | import software.amazon.awssdk.core.sync.RequestBody;
|
40 | 45 | import software.amazon.awssdk.http.ContentStreamProvider;
|
| 46 | +import software.amazon.awssdk.http.SdkHttpFullRequest; |
| 47 | +import software.amazon.awssdk.http.SdkHttpMethod; |
| 48 | +import software.amazon.awssdk.http.SdkHttpRequest; |
41 | 49 | import software.amazon.awssdk.http.SdkHttpResponse;
|
42 | 50 | import software.amazon.awssdk.services.s3.S3Configuration;
|
43 | 51 | import software.amazon.awssdk.services.s3.checksums.ChecksumCalculatingInputStream;
|
44 | 52 | import software.amazon.awssdk.services.s3.checksums.ChecksumValidatingInputStream;
|
45 | 53 | import software.amazon.awssdk.services.s3.internal.handlers.SyncChecksumValidationInterceptor.ChecksumCalculatingStreamProvider;
|
46 | 54 | import software.amazon.awssdk.services.s3.model.GetObjectRequest;
|
47 | 55 | import software.amazon.awssdk.services.s3.model.PutObjectRequest;
|
| 56 | +import software.amazon.awssdk.services.s3.model.PutObjectResponse; |
48 | 57 | import software.amazon.awssdk.services.s3.utils.InterceptorTestUtils;
|
49 | 58 | import software.amazon.awssdk.utils.IoUtils;
|
50 | 59 | import software.amazon.awssdk.utils.StringInputStream;
|
| 60 | +import software.amazon.awssdk.utils.internal.Base16Lower; |
51 | 61 |
|
52 | 62 | public class SyncChecksumValidationInterceptorTest {
|
53 | 63 |
|
| 64 | + private static final byte[] CONTENT_BYTES = "CONTENT".getBytes(Charset.forName("UTF-8")); |
| 65 | + private static final String VALID_CHECKSUM = Base16Lower.encodeAsString(checkSumFor(CONTENT_BYTES).getChecksumBytes()); |
| 66 | + private static final String INVALID_CHECKSUM = "3902ee7e149eb8313a34757e89e21af6"; |
| 67 | + |
54 | 68 | private SyncChecksumValidationInterceptor interceptor = new SyncChecksumValidationInterceptor();
|
55 | 69 |
|
56 | 70 | @Test
|
@@ -149,6 +163,73 @@ public void checksumCalculatingStreamProvider_shouldReturnNewStreamResetChecksum
|
149 | 163 | newStream.close();
|
150 | 164 | }
|
151 | 165 |
|
| 166 | + @Test |
| 167 | + public void afterUnmarshalling_putObjectRequest_shouldValidateChecksum() { |
| 168 | + SdkHttpResponse sdkHttpResponse = getSdkHttpResponseWithChecksumHeader(); |
| 169 | + |
| 170 | + PutObjectResponse response = PutObjectResponse.builder() |
| 171 | + .eTag(VALID_CHECKSUM) |
| 172 | + .build(); |
| 173 | + |
| 174 | + PutObjectRequest putObjectRequest = PutObjectRequest.builder() |
| 175 | + .build(); |
| 176 | + |
| 177 | + SdkHttpRequest sdkHttpRequest = SdkHttpFullRequest.builder() |
| 178 | + .uri(URI.create("http://localhost:8080")) |
| 179 | + .method(SdkHttpMethod.PUT) |
| 180 | + .build(); |
| 181 | + |
| 182 | + Context.AfterUnmarshalling afterUnmarshallingContext = |
| 183 | + InterceptorTestUtils.afterUnmarshallingContext(putObjectRequest, sdkHttpRequest, response, sdkHttpResponse); |
| 184 | + |
| 185 | + interceptor.afterUnmarshalling(afterUnmarshallingContext, getExecutionAttributesWithChecksum()); |
| 186 | + } |
| 187 | + |
| 188 | + @Test |
| 189 | + public void afterUnmarshalling_putObjectRequest_shouldValidateChecksum_throwExceptionIfInvalid() { |
| 190 | + SdkHttpResponse sdkHttpResponse = getSdkHttpResponseWithChecksumHeader(); |
| 191 | + |
| 192 | + PutObjectResponse response = PutObjectResponse.builder() |
| 193 | + .eTag(INVALID_CHECKSUM) |
| 194 | + .build(); |
| 195 | + |
| 196 | + PutObjectRequest putObjectRequest = PutObjectRequest.builder().build(); |
| 197 | + |
| 198 | + SdkHttpRequest sdkHttpRequest = SdkHttpFullRequest.builder() |
| 199 | + .uri(URI.create("http://localhost:8080")) |
| 200 | + .method(SdkHttpMethod.PUT) |
| 201 | + .build(); |
| 202 | + |
| 203 | + Context.AfterUnmarshalling afterUnmarshallingContext = |
| 204 | + InterceptorTestUtils.afterUnmarshallingContext(putObjectRequest, sdkHttpRequest, response, sdkHttpResponse); |
| 205 | + |
| 206 | + assertThatThrownBy(() -> interceptor.afterUnmarshalling(afterUnmarshallingContext, getExecutionAttributesWithChecksum())) |
| 207 | + .hasMessage("Data read has a different checksum than expected."); |
| 208 | + } |
| 209 | + |
| 210 | + @Test |
| 211 | + public void afterUnmarshalling_putObjectRequest_with_SSE_shouldNotValidateChecksum() { |
| 212 | + SdkHttpResponse sdkHttpResponse = getSdkHttpResponseWithChecksumHeader(); |
| 213 | + |
| 214 | + PutObjectResponse response = PutObjectResponse.builder() |
| 215 | + .eTag(INVALID_CHECKSUM) |
| 216 | + .build(); |
| 217 | + |
| 218 | + PutObjectRequest putObjectRequest = PutObjectRequest.builder().build(); |
| 219 | + |
| 220 | + SdkHttpRequest sdkHttpRequest = SdkHttpFullRequest.builder() |
| 221 | + .putHeader(SERVER_SIDE_ENCRYPTION_HEADER, AWS_KMS.toString()) |
| 222 | + .putHeader("x-amz-server-side-encryption-aws-kms-key-id", ENABLE_MD5_CHECKSUM_HEADER_VALUE) |
| 223 | + .uri(URI.create("http://localhost:8080")) |
| 224 | + .method(SdkHttpMethod.PUT) |
| 225 | + .build(); |
| 226 | + |
| 227 | + Context.AfterUnmarshalling afterUnmarshallingContext = |
| 228 | + InterceptorTestUtils.afterUnmarshallingContext(putObjectRequest, sdkHttpRequest, response, sdkHttpResponse); |
| 229 | + |
| 230 | + interceptor.afterUnmarshalling(afterUnmarshallingContext, getExecutionAttributesWithChecksum()); |
| 231 | + } |
| 232 | + |
152 | 233 | private static final class CloseAwareStream extends InputStream {
|
153 | 234 | private StringInputStream inputStream;
|
154 | 235 | private boolean isClosed;
|
@@ -192,4 +273,15 @@ private ExecutionAttributes getExecutionAttributesWithChecksumDisabled() {
|
192 | 273 | executionAttributes.putAttribute(SERVICE_CONFIG, S3Configuration.builder().checksumValidationEnabled(false).build());
|
193 | 274 | return executionAttributes;
|
194 | 275 | }
|
| 276 | + |
| 277 | + private ExecutionAttributes getExecutionAttributesWithChecksum() { |
| 278 | + SdkChecksum checksum = checkSumFor(CONTENT_BYTES); |
| 279 | + return getExecutionAttributes().putAttribute(CHECKSUM, checksum); |
| 280 | + } |
| 281 | + |
| 282 | + private static SdkChecksum checkSumFor(byte[] bytes) { |
| 283 | + SdkChecksum checksum = new Md5Checksum(); |
| 284 | + checksum.update(bytes, 0, bytes.length); |
| 285 | + return checksum; |
| 286 | + } |
195 | 287 | }
|
0 commit comments