Skip to content

Commit 58ee9bc

Browse files
authored
fix: handle contentLength in request object (#106)
1 parent 87411c8 commit 58ee9bc

File tree

2 files changed

+80
-27
lines changed

2 files changed

+80
-27
lines changed

src/main/java/software/amazon/encryption/s3/internal/PutEncryptedObjectPipeline.java

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import software.amazon.awssdk.services.s3.S3AsyncClient;
66
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
77
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
8+
import software.amazon.encryption.s3.S3EncryptionClientException;
89
import software.amazon.encryption.s3.materials.CryptographicMaterialsManager;
910
import software.amazon.encryption.s3.materials.EncryptionMaterials;
1011
import software.amazon.encryption.s3.materials.EncryptionMaterialsRequest;
@@ -33,17 +34,38 @@ private PutEncryptedObjectPipeline(Builder builder) {
3334
}
3435

3536
public CompletableFuture<PutObjectResponse> putObject(PutObjectRequest request, AsyncRequestBody requestBody) {
36-
EncryptionMaterialsRequest.Builder requestBuilder = EncryptionMaterialsRequest.builder()
37+
final Long contentLength;
38+
if (request.contentLength() != null) {
39+
if (requestBody.contentLength().isPresent() && !request.contentLength().equals(requestBody.contentLength().get())) {
40+
// if the contentLength values do not match, throw an exception, since we don't know which is correct
41+
throw new S3EncryptionClientException("The contentLength provided in the request object MUST match the " +
42+
"contentLength in the request body");
43+
} else if (!requestBody.contentLength().isPresent()) {
44+
// no contentLength in request body, use the one in request
45+
contentLength = request.contentLength();
46+
} else {
47+
// only remaining case is when the values match, so either works here
48+
contentLength = request.contentLength();
49+
}
50+
} else {
51+
contentLength = requestBody.contentLength().orElse(-1L);
52+
}
53+
54+
EncryptionMaterialsRequest encryptionMaterialsRequest = EncryptionMaterialsRequest.builder()
3755
.s3Request(request)
38-
.plaintextLength(requestBody.contentLength().orElse(-1L));
56+
.plaintextLength(contentLength)
57+
.build();
3958

40-
EncryptionMaterials materials = _cryptoMaterialsManager.getEncryptionMaterials(requestBuilder.build());
59+
EncryptionMaterials materials = _cryptoMaterialsManager.getEncryptionMaterials(encryptionMaterialsRequest);
4160

4261
EncryptedContent encryptedContent = _asyncContentEncryptionStrategy.encryptContent(materials, requestBody);
4362

4463
Map<String, String> metadata = new HashMap<>(request.metadata());
4564
metadata = _contentMetadataEncodingStrategy.encodeMetadata(materials, encryptedContent.getNonce(), metadata);
46-
PutObjectRequest encryptedPutRequest = request.toBuilder().metadata(metadata).build();
65+
PutObjectRequest encryptedPutRequest = request.toBuilder()
66+
.contentLength(encryptedContent.getCiphertextLength())
67+
.metadata(metadata)
68+
.build();
4769
return _s3AsyncClient.putObject(encryptedPutRequest, encryptedContent.getAsyncCiphertext());
4870
}
4971

src/test/java/software/amazon/encryption/s3/S3EncryptionClientTest.java

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -511,29 +511,6 @@ public void s3EncryptionClientFromAESKeyringUsesDifferentSecureRandomThanKeyring
511511
v3Client.close();
512512
}
513513

514-
/**
515-
* A simple, reusable round-trip (encryption + decryption) using a given
516-
* S3Client. Useful for testing client configuration.
517-
*
518-
* @param v3Client the client under test
519-
*/
520-
private void simpleV3RoundTrip(final S3Client v3Client, final String objectKey) {
521-
final String input = "SimpleTestOfV3EncryptionClient";
522-
523-
v3Client.putObject(builder -> builder
524-
.bucket(BUCKET)
525-
.key(objectKey)
526-
.build(),
527-
RequestBody.fromString(input));
528-
529-
ResponseBytes<GetObjectResponse> objectResponse = v3Client.getObjectAsBytes(builder -> builder
530-
.bucket(BUCKET)
531-
.key(objectKey)
532-
.build());
533-
String output = objectResponse.asUtf8String();
534-
assertEquals(input, output);
535-
}
536-
537514
@Test
538515
public void cryptoProviderV3toV3Enabled() {
539516
final String objectKey = appendTestSuffix("crypto-provider-enabled-v3-to-v3");
@@ -599,4 +576,58 @@ public void cryptoProviderV2toV3Enabled() {
599576
deleteObject(BUCKET, objectKey, v3Client);
600577
v3Client.close();
601578
}
579+
580+
@Test
581+
public void contentLengthRequest() {
582+
final String objectKey = appendTestSuffix("content-length");
583+
584+
S3Client s3EncryptionClient = S3EncryptionClient.builder()
585+
.kmsKeyId(KMS_KEY_ID)
586+
.build();
587+
588+
final String input = "SimpleTestOfV3EncryptionClientCopyObject";
589+
final int inputLength = input.length();
590+
591+
s3EncryptionClient.putObject(builder -> builder
592+
.bucket(BUCKET)
593+
.key(objectKey)
594+
.contentLength((long) inputLength)
595+
.build(),
596+
RequestBody.fromString(input));
597+
598+
ResponseBytes<GetObjectResponse> objectResponse = s3EncryptionClient.getObjectAsBytes(builder -> builder
599+
.bucket(BUCKET)
600+
.key(objectKey)
601+
.build());
602+
String output = objectResponse.asUtf8String();
603+
assertEquals(input, output);
604+
605+
// Cleanup
606+
deleteObject(BUCKET, objectKey, s3EncryptionClient);
607+
s3EncryptionClient.close();
608+
}
609+
610+
/**
611+
* A simple, reusable round-trip (encryption + decryption) using a given
612+
* S3Client. Useful for testing client configuration.
613+
*
614+
* @param v3Client the client under test
615+
*/
616+
private void simpleV3RoundTrip(final S3Client v3Client, final String objectKey) {
617+
final String input = "SimpleTestOfV3EncryptionClient";
618+
619+
v3Client.putObject(builder -> builder
620+
.bucket(BUCKET)
621+
.key(objectKey)
622+
.build(),
623+
RequestBody.fromString(input));
624+
625+
ResponseBytes<GetObjectResponse> objectResponse = v3Client.getObjectAsBytes(builder -> builder
626+
.bucket(BUCKET)
627+
.key(objectKey)
628+
.build());
629+
String output = objectResponse.asUtf8String();
630+
assertEquals(input, output);
631+
}
632+
602633
}

0 commit comments

Comments
 (0)