Skip to content

Commit 1c0b19f

Browse files
authored
allowlist for copy request added (#6352)
* allowlist for copy request added * changelog added * change the validation condition to only check if the set field is different than the value in target pojo * change to Objects.equal
1 parent dcd4287 commit 1c0b19f

File tree

3 files changed

+149
-18
lines changed

3 files changed

+149
-18
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": "Added allowlist when copying PutObjectRequest and CopyObjectRequest to transfer manager request"
6+
}

services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/multipart/SdkPojoConversionUtils.java

Lines changed: 143 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
import java.util.HashSet;
2121
import java.util.List;
2222
import java.util.Map;
23+
import java.util.Objects;
2324
import java.util.Set;
2425
import software.amazon.awssdk.annotations.SdkInternalApi;
2526
import software.amazon.awssdk.core.SdkField;
2627
import software.amazon.awssdk.core.SdkPojo;
28+
import software.amazon.awssdk.core.exception.SdkClientException;
2729
import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
2830
import software.amazon.awssdk.services.s3.model.ChecksumType;
2931
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
@@ -53,12 +55,104 @@ public final class SdkPojoConversionUtils {
5355
new HashSet<>(Arrays.asList("ChecksumSHA1", "ChecksumSHA256", "ContentMD5", "ChecksumCRC32C", "ChecksumCRC32",
5456
"ChecksumCRC64NVME", "ContentLength"));
5557

58+
private static final Set<String> PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS = new HashSet<>(Arrays.asList(
59+
"ACL",
60+
"Bucket",
61+
"CacheControl",
62+
"ContentDisposition",
63+
"ContentEncoding",
64+
"ContentLanguage",
65+
"ContentLength",
66+
"ContentMD5",
67+
"ContentType",
68+
"ChecksumAlgorithm",
69+
"ChecksumCRC32",
70+
"ChecksumCRC32C",
71+
"ChecksumCRC64NVME",
72+
"ChecksumSHA1",
73+
"ChecksumSHA256",
74+
"Expires",
75+
"IfMatch",
76+
"IfNoneMatch",
77+
"GrantFullControl",
78+
"GrantRead",
79+
"GrantReadACP",
80+
"GrantWriteACP",
81+
"Key",
82+
"WriteOffsetBytes",
83+
"Metadata",
84+
"ServerSideEncryption",
85+
"StorageClass",
86+
"WebsiteRedirectLocation",
87+
"SSECustomerAlgorithm",
88+
"SSECustomerKey",
89+
"SSECustomerKeyMD5",
90+
"SSEKMSKeyId",
91+
"SSEKMSEncryptionContext",
92+
"BucketKeyEnabled",
93+
"RequestPayer",
94+
"Tagging",
95+
"ObjectLockMode",
96+
"ObjectLockRetainUntilDate",
97+
"ObjectLockLegalHoldStatus",
98+
"ExpectedBucketOwner"
99+
));
100+
101+
private static final Set<String> COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS = new HashSet<>(Arrays.asList(
102+
"ACL",
103+
"CacheControl",
104+
"ChecksumAlgorithm",
105+
"ContentDisposition",
106+
"ContentEncoding",
107+
"ContentLanguage",
108+
"ContentType",
109+
"CopySource",
110+
"CopySourceIfMatch",
111+
"CopySourceIfModifiedSince",
112+
"CopySourceIfNoneMatch",
113+
"CopySourceIfUnmodifiedSince",
114+
"CopySourceSSECustomerAlgorithm",
115+
"CopySourceSSECustomerKey",
116+
"CopySourceSSECustomerKeyMD5",
117+
"DestinationBucket",
118+
"DestinationKey",
119+
"Expires",
120+
"GrantFullControl",
121+
"GrantRead",
122+
"GrantReadACP",
123+
"GrantWriteACP",
124+
"Metadata",
125+
"MetadataDirective",
126+
"TaggingDirective",
127+
"ServerSideEncryption",
128+
"SourceBucket",
129+
"SourceKey",
130+
"SourceVersionId",
131+
"StorageClass",
132+
"WebsiteRedirectLocation",
133+
"SSECustomerAlgorithm",
134+
"SSECustomerKey",
135+
"SSECustomerKeyMD5",
136+
"SSEKMSKeyId",
137+
"SSEKMSEncryptionContext",
138+
"BucketKeyEnabled",
139+
"RequestPayer",
140+
"Tagging",
141+
"ObjectLockMode",
142+
"ObjectLockRetainUntilDate",
143+
"ObjectLockLegalHoldStatus",
144+
"ExpectedBucketOwner",
145+
"ExpectedSourceBucketOwner"
146+
));
147+
148+
56149
private SdkPojoConversionUtils() {
57150
}
58151

59152
public static UploadPartRequest toUploadPartRequest(PutObjectRequest putObjectRequest, int partNumber, String uploadId) {
60153

61154
UploadPartRequest.Builder builder = UploadPartRequest.builder();
155+
validateRequestFields(putObjectRequest, builder.build(), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
62156
setSdkFields(builder, putObjectRequest, PUT_OBJECT_REQUEST_TO_UPLOAD_PART_FIELDS_TO_IGNORE);
63157
return builder.uploadId(uploadId).partNumber(partNumber).build();
64158
}
@@ -67,6 +161,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
67161
String uploadId, CompletedPart[] parts,
68162
long contentLength) {
69163
CompleteMultipartUploadRequest.Builder builder = CompleteMultipartUploadRequest.builder();
164+
validateRequestFields(putObjectRequest, builder.build(), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
70165
setSdkFields(builder, putObjectRequest);
71166

72167
builder.mpuObjectSize(contentLength);
@@ -81,6 +176,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
81176
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest(PutObjectRequest putObjectRequest) {
82177

83178
CreateMultipartUploadRequest.Builder builder = CreateMultipartUploadRequest.builder();
179+
validateRequestFields(putObjectRequest, builder.build(), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
84180
setSdkFields(builder, putObjectRequest);
85181

86182
if (S3ChecksumUtils.checksumValueSpecified(putObjectRequest)) {
@@ -130,29 +226,14 @@ public static CompletedPart toCompletedPart(Part part) {
130226

131227
public static ListPartsRequest toListPartsRequest(String uploadId, PutObjectRequest putObjectRequest) {
132228
ListPartsRequest.Builder builder = ListPartsRequest.builder();
229+
validateRequestFields(putObjectRequest, builder.build(), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
133230
setSdkFields(builder, putObjectRequest);
134231
return builder.uploadId(uploadId).build();
135232
}
136233

137-
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject) {
138-
setSdkFields(targetBuilder, sourceObject, new HashSet<>());
139-
}
140-
141-
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject, Set<String> fieldsToIgnore) {
142-
Map<String, Object> sourceFields = retrieveSdkFields(sourceObject, sourceObject.sdkFields());
143-
List<SdkField<?>> targetSdkFields = targetBuilder.sdkFields();
144-
145-
for (SdkField<?> field : targetSdkFields) {
146-
if (fieldsToIgnore.contains(field.memberName())) {
147-
continue;
148-
}
149-
field.set(targetBuilder, sourceFields.getOrDefault(field.memberName(), null));
150-
}
151-
}
152-
153234
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest(CopyObjectRequest copyObjectRequest) {
154235
CreateMultipartUploadRequest.Builder builder = CreateMultipartUploadRequest.builder();
155-
236+
validateRequestFields(copyObjectRequest, builder.build(), COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS);
156237
setSdkFields(builder, copyObjectRequest);
157238
builder.bucket(copyObjectRequest.destinationBucket());
158239
builder.key(copyObjectRequest.destinationKey());
@@ -180,6 +261,7 @@ private static CopyObjectResult toCopyObjectResult(CompleteMultipartUploadRespon
180261

181262
public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(CopyObjectRequest copyObjectRequest) {
182263
AbortMultipartUploadRequest.Builder builder = AbortMultipartUploadRequest.builder();
264+
validateRequestFields(copyObjectRequest, builder.build(), COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS);
183265
setSdkFields(builder, copyObjectRequest);
184266
builder.bucket(copyObjectRequest.destinationBucket());
185267
builder.key(copyObjectRequest.destinationKey());
@@ -188,6 +270,7 @@ public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(
188270

189271
public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(PutObjectRequest putObjectRequest) {
190272
AbortMultipartUploadRequest.Builder builder = AbortMultipartUploadRequest.builder();
273+
validateRequestFields(putObjectRequest, builder.build(), PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
191274
setSdkFields(builder, putObjectRequest);
192275
return builder;
193276
}
@@ -225,4 +308,47 @@ private static Map<String, Object> retrieveSdkFields(SdkPojo sourceObject, List<
225308
field.getValueOrDefault(sourceObject)),
226309
Map::putAll);
227310
}
311+
312+
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject) {
313+
setSdkFields(targetBuilder, sourceObject, new HashSet<>());
314+
}
315+
316+
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject, Set<String> fieldsToIgnore) {
317+
Map<String, Object> sourceFields = retrieveSdkFields(sourceObject, sourceObject.sdkFields());
318+
List<SdkField<?>> targetSdkFields = targetBuilder.sdkFields();
319+
320+
for (SdkField<?> field : targetSdkFields) {
321+
if (fieldsToIgnore.contains(field.memberName())) {
322+
continue;
323+
}
324+
field.set(targetBuilder, sourceFields.getOrDefault(field.memberName(), null));
325+
}
326+
}
327+
328+
private static void validateRequestFields(SdkPojo sourceObject, SdkPojo targetObject, Set<String> allowedFields) {
329+
Set<String> invalidFields = new HashSet<>();
330+
331+
for (SdkField<?> sourceField : sourceObject.sdkFields()) {
332+
String fieldName = sourceField.memberName();
333+
Object sourceValue = sourceField.getValueOrDefault(sourceObject);
334+
335+
if (!allowedFields.contains(fieldName)) {
336+
SdkField<?> targetField = targetObject.sdkFields()
337+
.stream()
338+
.filter(field -> field.memberName().equals(fieldName))
339+
.findFirst()
340+
.orElse(null);
341+
if (targetField != null && !Objects.equals(sourceValue, targetField.getValueOrDefault(targetObject))) {
342+
invalidFields.add(fieldName);
343+
}
344+
}
345+
}
346+
347+
if (!invalidFields.isEmpty()) {
348+
throw SdkClientException.create(
349+
String.format("The following fields are not allowed: %s",
350+
String.join(", ", invalidFields))
351+
);
352+
}
353+
}
228354
}

services/s3/src/test/java/software/amazon/awssdk/services/s3/internal/multipart/SdkPojoConversionUtilsTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import software.amazon.awssdk.core.SdkField;
3737
import software.amazon.awssdk.core.SdkPojo;
3838
import software.amazon.awssdk.http.SdkHttpFullResponse;
39-
import software.amazon.awssdk.services.s3.internal.multipart.SdkPojoConversionUtils;
4039
import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
4140
import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm;
4241
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;

0 commit comments

Comments
 (0)