Skip to content

Commit cce84bf

Browse files
committed
allowlist for copy request added
1 parent 303d19b commit cce84bf

File tree

1 file changed

+135
-17
lines changed

1 file changed

+135
-17
lines changed

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

Lines changed: 135 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import software.amazon.awssdk.annotations.SdkInternalApi;
2525
import software.amazon.awssdk.core.SdkField;
2626
import software.amazon.awssdk.core.SdkPojo;
27+
import software.amazon.awssdk.core.exception.SdkClientException;
2728
import software.amazon.awssdk.services.s3.model.AbortMultipartUploadRequest;
2829
import software.amazon.awssdk.services.s3.model.ChecksumType;
2930
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest;
@@ -53,12 +54,104 @@ public final class SdkPojoConversionUtils {
5354
new HashSet<>(Arrays.asList("ChecksumSHA1", "ChecksumSHA256", "ContentMD5", "ChecksumCRC32C", "ChecksumCRC32",
5455
"ChecksumCRC64NVME", "ContentLength"));
5556

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

59151
public static UploadPartRequest toUploadPartRequest(PutObjectRequest putObjectRequest, int partNumber, String uploadId) {
60152

61153
UploadPartRequest.Builder builder = UploadPartRequest.builder();
154+
validateRequestFields(putObjectRequest, PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
62155
setSdkFields(builder, putObjectRequest, PUT_OBJECT_REQUEST_TO_UPLOAD_PART_FIELDS_TO_IGNORE);
63156
return builder.uploadId(uploadId).partNumber(partNumber).build();
64157
}
@@ -67,6 +160,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
67160
String uploadId, CompletedPart[] parts,
68161
long contentLength) {
69162
CompleteMultipartUploadRequest.Builder builder = CompleteMultipartUploadRequest.builder();
163+
validateRequestFields(putObjectRequest, PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
70164
setSdkFields(builder, putObjectRequest);
71165

72166
builder.mpuObjectSize(contentLength);
@@ -81,6 +175,7 @@ public static CompleteMultipartUploadRequest toCompleteMultipartUploadRequest(Pu
81175
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest(PutObjectRequest putObjectRequest) {
82176

83177
CreateMultipartUploadRequest.Builder builder = CreateMultipartUploadRequest.builder();
178+
validateRequestFields(putObjectRequest, PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
84179
setSdkFields(builder, putObjectRequest);
85180

86181
if (S3ChecksumUtils.checksumValueSpecified(putObjectRequest)) {
@@ -130,29 +225,14 @@ public static CompletedPart toCompletedPart(Part part) {
130225

131226
public static ListPartsRequest toListPartsRequest(String uploadId, PutObjectRequest putObjectRequest) {
132227
ListPartsRequest.Builder builder = ListPartsRequest.builder();
228+
validateRequestFields(putObjectRequest, PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
133229
setSdkFields(builder, putObjectRequest);
134230
return builder.uploadId(uploadId).build();
135231
}
136232

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-
153233
public static CreateMultipartUploadRequest toCreateMultipartUploadRequest(CopyObjectRequest copyObjectRequest) {
154234
CreateMultipartUploadRequest.Builder builder = CreateMultipartUploadRequest.builder();
155-
235+
validateRequestFields(copyObjectRequest, COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS);
156236
setSdkFields(builder, copyObjectRequest);
157237
builder.bucket(copyObjectRequest.destinationBucket());
158238
builder.key(copyObjectRequest.destinationKey());
@@ -180,6 +260,7 @@ private static CopyObjectResult toCopyObjectResult(CompleteMultipartUploadRespon
180260

181261
public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(CopyObjectRequest copyObjectRequest) {
182262
AbortMultipartUploadRequest.Builder builder = AbortMultipartUploadRequest.builder();
263+
validateRequestFields(copyObjectRequest, COPY_OBJECT_TO_COPY_OBJECT_ALLOWED_FIELDS);
183264
setSdkFields(builder, copyObjectRequest);
184265
builder.bucket(copyObjectRequest.destinationBucket());
185266
builder.key(copyObjectRequest.destinationKey());
@@ -188,6 +269,7 @@ public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(
188269

189270
public static AbortMultipartUploadRequest.Builder toAbortMultipartUploadRequest(PutObjectRequest putObjectRequest) {
190271
AbortMultipartUploadRequest.Builder builder = AbortMultipartUploadRequest.builder();
272+
validateRequestFields(putObjectRequest, PUT_OBJECT_TO_UPLOAD_PART_ALLOWED_FIELDS);
191273
setSdkFields(builder, putObjectRequest);
192274
return builder;
193275
}
@@ -225,4 +307,40 @@ private static Map<String, Object> retrieveSdkFields(SdkPojo sourceObject, List<
225307
field.getValueOrDefault(sourceObject)),
226308
Map::putAll);
227309
}
310+
311+
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject) {
312+
setSdkFields(targetBuilder, sourceObject, new HashSet<>());
313+
}
314+
315+
private static void setSdkFields(SdkPojo targetBuilder, SdkPojo sourceObject, Set<String> fieldsToIgnore) {
316+
Map<String, Object> sourceFields = retrieveSdkFields(sourceObject, sourceObject.sdkFields());
317+
List<SdkField<?>> targetSdkFields = targetBuilder.sdkFields();
318+
319+
for (SdkField<?> field : targetSdkFields) {
320+
if (fieldsToIgnore.contains(field.memberName())) {
321+
continue;
322+
}
323+
field.set(targetBuilder, sourceFields.getOrDefault(field.memberName(), null));
324+
}
325+
}
326+
327+
private static void validateRequestFields(SdkPojo sourceObject, Set<String> allowedFields) {
328+
Set<String> invalidFields = new HashSet<>();
329+
330+
for (SdkField<?> sourceField : sourceObject.sdkFields()) {
331+
String fieldName = sourceField.memberName();
332+
Object rawValue = sourceField.getValueOrDefault(sourceObject);
333+
334+
if (rawValue != null && !allowedFields.contains(fieldName)) {
335+
invalidFields.add(fieldName);
336+
}
337+
}
338+
339+
if (!invalidFields.isEmpty()) {
340+
throw SdkClientException.create(
341+
String.format("The following fields are not allowed: %s",
342+
String.join(", ", invalidFields))
343+
);
344+
}
345+
}
228346
}

0 commit comments

Comments
 (0)