From ba2fe995dfd5206a1d490ff5beb1af73d016bd12 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 4 Feb 2025 13:30:52 -0800 Subject: [PATCH 01/10] Decouple policy logic from resource url for getSignedUrlWithCustomPolicy --- .../cloudfront/CloudFrontUtilities.java | 8 +- .../internal/utils/SigningUtils.java | 9 +- .../cloudfront/model/CustomSignerRequest.java | 27 +++- .../CloudFrontUtilitiesIntegrationTest.java | 116 ++++++++++++++++++ .../cloudfront/CloudFrontUtilitiesTest.java | 36 ++++++ 5 files changed, 187 insertions(+), 9 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index 6d1f7eae2e2f..46f08cb72e8f 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -249,8 +249,12 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer { - private final String resourceUrl; private final PrivateKey privateKey; private final String keyPairId; private final Instant expirationDate; private final Instant activeDate; private final String ipRange; + private final String policyResourceUrl; private CustomSignerRequest(DefaultBuilder builder) { this.resourceUrl = builder.resourceUrl; @@ -50,6 +50,7 @@ private CustomSignerRequest(DefaultBuilder builder) { this.expirationDate = builder.expirationDate; this.activeDate = builder.activeDate; this.ipRange = builder.ipRange; + this.policyResourceUrl = builder.policyResourceUrl; } /** @@ -99,6 +100,8 @@ public String ipRange() { return ipRange; } + public String policyResourceUrl() { return policyResourceUrl; } + @Override public boolean equals(Object o) { if (this == o) { @@ -114,7 +117,8 @@ public boolean equals(Object o) { && Objects.equals(keyPairId, cookie.keyPairId) && Objects.equals(expirationDate, cookie.expirationDate) && Objects.equals(activeDate, cookie.activeDate) - && Objects.equals(ipRange, cookie.ipRange); + && Objects.equals(ipRange, cookie.ipRange) + && Objects.equals(policyResourceUrl, cookie.policyResourceUrl); } @Override @@ -125,6 +129,7 @@ public int hashCode() { result = 31 * result + (expirationDate != null ? expirationDate.hashCode() : 0); result = 31 * result + (activeDate != null ? activeDate.hashCode() : 0); result = 31 * result + (ipRange != null ? ipRange.hashCode() : 0); + result = 31 * result + (policyResourceUrl != null ? policyResourceUrl.hashCode() : 0); return result; } @@ -179,6 +184,16 @@ public interface Builder extends CopyableBuilder + * For custom policies, this specifies the URL pattern that determines which files + * can be accessed with this signed URL. This can include wildcard characters (*) to + * grant access to multiple files or paths. If not specified, the resourceUrl value + * will be used in the policy. + */ + Builder policyResourceUrl(String policyResourceUrl); } private static final class DefaultBuilder implements Builder { @@ -188,6 +203,7 @@ private static final class DefaultBuilder implements Builder { private Instant expirationDate; private Instant activeDate; private String ipRange; + private String policyResourceUrl; private DefaultBuilder() { } @@ -199,6 +215,7 @@ private DefaultBuilder(CustomSignerRequest request) { this.expirationDate = request.expirationDate; this.activeDate = request.activeDate; this.ipRange = request.ipRange; + this.policyResourceUrl = request.policyResourceUrl; } @Override @@ -243,6 +260,12 @@ public Builder ipRange(String ipRange) { return this; } + @Override + public Builder policyResourceUrl(String policyResourceUrl) { + this.policyResourceUrl = policyResourceUrl; + return this; + } + @Override public CustomSignerRequest build() { return new CustomSignerRequest(this); diff --git a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java index 97570628251e..a744bba62624 100644 --- a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java +++ b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java @@ -21,6 +21,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; @@ -77,6 +78,9 @@ public class CloudFrontUtilitiesIntegrationTest extends IntegrationTestBase { private static final String RESOURCE_PREFIX = "do-not-delete-cf-test-"; private static final String CALLER_REFERENCE = UUID.randomUUID().toString(); private static final String S3_OBJECT_KEY = "s3ObjectKey"; + private static final String S3_OBJECT_KEY_ON_SUB_PATH = "foo/specific-file"; + private static final String S3_OBJECT_KEY_ON_SUB_PATH_OTHER = "foo/other-file"; + private static String bucket; private static String domainName; @@ -267,6 +271,114 @@ void getCookiesForCustomPolicy_withFutureActiveDate_shouldReturn403Response() th assertThat(response.httpResponse().statusCode()).isEqualTo(expectedStatus); } + @Test + void getSignedUrlWithCustomPolicy_shouldAllowQueryParametersWhenUsingWildcard() throws Exception { + Instant expirationDate = LocalDate.of(2050, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + Instant activeDate = LocalDate.of(2022, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + CustomSignerRequest request = CustomSignerRequest.builder() + .resourceUrl(resourceUrl) + .privateKey(keyFilePath) + .keyPairId(keyPairId) + .policyResourceUrl(resourceUrl + "*") + .activeDate(activeDate) + .expirationDate(expirationDate) + .build(); + + SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCustomPolicy(request); + + String urlWithDynamicParam = signedUrl.url() + "&foo=bar"; + URI modifiedUri = URI.create(urlWithDynamicParam); + + + SdkHttpClient client = ApacheHttpClient.create(); + HttpExecuteResponse response = client.prepareRequest(HttpExecuteRequest.builder() + .request(SdkHttpRequest.builder() + .encodedPath(modifiedUri.getRawPath() + "?" + modifiedUri.getRawQuery()) + .host(modifiedUri.getHost()) + .method(SdkHttpMethod.GET) + .protocol("https") + .build()) + .build()).call(); + assertThat(response.httpResponse().statusCode()).isEqualTo(200); + } + + @Test + void getSignedUrlWithCustomPolicy_wildCardPath() throws Exception { + String resourceUri = "https://" + domainName; + Instant expirationDate = LocalDate.of(2050, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + Instant activeDate = LocalDate.of(2022, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + CustomSignerRequest request = CustomSignerRequest.builder() + .resourceUrl(resourceUri + "/foo/specific-file") + .privateKey(keyFilePath) + .keyPairId(keyPairId) + .policyResourceUrl(resourceUri + "/foo/*") + .activeDate(activeDate) + .expirationDate(expirationDate) + .build(); + + SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCustomPolicy(request); + + + URI modifiedUri = URI.create(signedUrl.url().replace("/specific-file","/other-file")); + SdkHttpClient client = ApacheHttpClient.create(); + HttpExecuteResponse response = client.prepareRequest(HttpExecuteRequest.builder() + .request(SdkHttpRequest.builder() + .encodedPath(modifiedUri.getRawPath() + "?" + modifiedUri.getRawQuery()) + .host(modifiedUri.getHost()) + .method(SdkHttpMethod.GET) + .protocol("https") + .build()) + .build()).call(); + assertThat(response.httpResponse().statusCode()).isEqualTo(200); + } + + @Test + void getSignedUrlWithCustomPolicy_wildCardPolicyResourceUrl_allowsAnyPath() throws Exception { + Instant expirationDate = LocalDate.of(2050, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + Instant activeDate = LocalDate.of(2022, 1, 1) + .atStartOfDay() + .toInstant(ZoneOffset.of("Z")); + + CustomSignerRequest request = CustomSignerRequest.builder() + .resourceUrl(resourceUrl) + .privateKey(keyFilePath) + .keyPairId(keyPairId) + .policyResourceUrl("*") + .activeDate(activeDate) + .expirationDate(expirationDate) + .build(); + + SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCustomPolicy(request); + + + URI modifiedUri = URI.create(signedUrl.url().replace("/s3ObjectKey","/foo/other-file")); + SdkHttpClient client = ApacheHttpClient.create(); + HttpExecuteResponse response = client.prepareRequest(HttpExecuteRequest.builder() + .request(SdkHttpRequest.builder() + .encodedPath(modifiedUri.getRawPath() + "?" + modifiedUri.getRawQuery()) + .host(modifiedUri.getHost()) + .method(SdkHttpMethod.GET) + .protocol("https") + .build()) + .build()).call(); + assertThat(response.httpResponse().statusCode()).isEqualTo(200); + } + private static void initStaticFields() throws Exception { initializeKeyFileAndPair(); originAccessId = getOrCreateOriginAccessIdentity(); @@ -409,7 +521,11 @@ private static String getOrCreateBucket() throws IOException { s3Client.waiter().waitUntilBucketExists(r -> r.bucket(newBucketName)); File content = new RandomTempFile("testFile", 1000L); + File content2 = new RandomTempFile("testFile2", 500L); s3Client.putObject(PutObjectRequest.builder().bucket(newBucketName).key(S3_OBJECT_KEY).build(), RequestBody.fromFile(content)); + s3Client.putObject(PutObjectRequest.builder().bucket(newBucketName).key(S3_OBJECT_KEY_ON_SUB_PATH).build(), RequestBody.fromFile(content2)); + s3Client.putObject(PutObjectRequest.builder().bucket(newBucketName).key(S3_OBJECT_KEY_ON_SUB_PATH_OTHER).build(), RequestBody.fromFile(content2)); + String bucketPolicy = "{\n" + "\"Version\":\"2012-10-17\",\n" diff --git a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesTest.java b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesTest.java index 06076a53e7d8..8e1f862c21a1 100644 --- a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesTest.java +++ b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesTest.java @@ -15,6 +15,7 @@ package software.amazon.awssdk.services.cloudfront; +import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -27,6 +28,7 @@ import java.time.Instant; import java.time.ZoneOffset; import java.util.Base64; +import java.util.StringJoiner; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -331,4 +333,38 @@ void getCookiesForCustomPolicy_withActiveDateAndIpRangeOmitted_producesValidCook assertThat(cookiesForCustomPolicy.keyPairIdHeaderValue()).isEqualTo("CloudFront-Key-Pair-Id=keyPairId"); } + @Test + void getSignedURLWithCustomPolicy_policyResourceUrlShouldOverwriteResourceUrl() { + String baseUrl = "https://d1234.cloudfront.net/images/photo.jpg"; + Instant expiration = Instant.now().plusSeconds(3600); + CustomSignerRequest request = CustomSignerRequest.builder() + .resourceUrl(baseUrl) + .privateKey(keyPair.getPrivate()) + .keyPairId("keyPairId") + .policyResourceUrl("*") + .expirationDate(expiration) + .build(); + + SignedUrl signedUrl = cloudFrontUtilities.getSignedUrlWithCustomPolicy(request); + + String encodedPolicy = signedUrl.url().split("Policy=")[1].split("&")[0]; + // Replace URL-safe characters back to standard Base64 + String standardBase64 = encodedPolicy + .replace('-', '+') + .replace('_', '=') + .replace('~', '/'); + String decodedPolicy = new String(Base64.getDecoder().decode(standardBase64), UTF_8); + StringBuilder expectedPolicy = new StringBuilder(); + StringJoiner conditions = new StringJoiner(",", "{", "}"); + + conditions.add("\"DateLessThan\":{\"AWS:EpochTime\":" + expiration.getEpochSecond() + "}"); + + + expectedPolicy.append("{\"Statement\": [{") + .append("\"Resource\":\"").append("*").append("\",") + .append("\"Condition\":").append(conditions) + .append("}]}"); + + assertThat(decodedPolicy.trim()).isEqualTo(expectedPolicy.toString().trim()); + } } From d6a3f5aeafd06261a9e63625b2c65ff42d082572 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 4 Feb 2025 13:51:05 -0800 Subject: [PATCH 02/10] Adding validation for resourceUrl to avoid NPE --- .../services/cloudfront/internal/utils/SigningUtils.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java index 916ab3f32a3f..7cb0badb273d 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java @@ -179,6 +179,9 @@ public static String buildCustomPolicyForSignedUrl(String resourceUrl, if (expirationDate == null) { throw SdkClientException.create("Expiration date must be provided to sign CloudFront URLs"); } + if (resourceUrl == null){ + throw SdkClientException.create("Resource URL must be provided to sign CloudFront URLs"); + } String policyResource = policyResourceUrl != null ? policyResourceUrl : resourceUrl; return buildCustomPolicy(policyResource, activeDate, expirationDate, limitToIpAddressCidr); } From 94519ac69f0d51f004094a7ec3d10bc7f310f730 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 4 Feb 2025 13:59:15 -0800 Subject: [PATCH 03/10] Add changelog --- .changes/next-release/bugfix-AmazonCloudfront-1fa6f75.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changes/next-release/bugfix-AmazonCloudfront-1fa6f75.json diff --git a/.changes/next-release/bugfix-AmazonCloudfront-1fa6f75.json b/.changes/next-release/bugfix-AmazonCloudfront-1fa6f75.json new file mode 100644 index 000000000000..de642fe94127 --- /dev/null +++ b/.changes/next-release/bugfix-AmazonCloudfront-1fa6f75.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "Amazon Cloudfront", + "contributor": "", + "description": "Decouple policy logic from resource url for getSignedUrlWithCustomPolicy" +} From c6823a351b15ab06cd9489fee4d5c174475118db Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 4 Feb 2025 15:01:47 -0800 Subject: [PATCH 04/10] Fix checkstyle --- .../services/cloudfront/internal/utils/SigningUtils.java | 2 +- .../awssdk/services/cloudfront/model/CustomSignerRequest.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java index 7cb0badb273d..2e6a77ae4c71 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/internal/utils/SigningUtils.java @@ -179,7 +179,7 @@ public static String buildCustomPolicyForSignedUrl(String resourceUrl, if (expirationDate == null) { throw SdkClientException.create("Expiration date must be provided to sign CloudFront URLs"); } - if (resourceUrl == null){ + if (resourceUrl == null) { throw SdkClientException.create("Resource URL must be provided to sign CloudFront URLs"); } String policyResource = policyResourceUrl != null ? policyResourceUrl : resourceUrl; diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.java index f8e6cdcfc0e3..988a8d6e1209 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/model/CustomSignerRequest.java @@ -100,7 +100,9 @@ public String ipRange() { return ipRange; } - public String policyResourceUrl() { return policyResourceUrl; } + public String policyResourceUrl() { + return policyResourceUrl; + } @Override public boolean equals(Object o) { From e67972eed42486ef3e3cd26a6353dd09376fe5bd Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Wed, 5 Feb 2025 22:33:32 -0800 Subject: [PATCH 05/10] Renaming resource policy, adding documentation, refactoring --- .../cloudfront/CloudFrontUtilities.java | 25 +++++++++++++++---- .../internal/utils/SigningUtils.java | 9 +++---- .../cloudfront/model/CustomSignerRequest.java | 22 ++++++++-------- .../CloudFrontUtilitiesIntegrationTest.java | 8 +++--- .../cloudfront/CloudFrontUtilitiesTest.java | 2 +- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index 46f08cb72e8f..2a28e1084930 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -210,13 +210,17 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer + * Note: If you require a wildcard or a different resource path in the policy than the actual {@code resourceUrl}, + * use the optional {@code policyResource} field in {@link CustomSignerRequest}. * For more information, see Creating a signed URL using a custom policy. * * @param request * A {@link CustomSignerRequest} configured with the following values: - * resourceUrl, privateKey, keyPairId, expirationDate, activeDate (optional), ipRange (optional) + * resourceUrl, privateKey, keyPairId, expirationDate, activeDate (optional), ipRange (optional), policyResource + * (optional) * @return A signed URL that will permit access to distribution and S3 * objects as specified in the policy document. * @@ -233,6 +237,7 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer Date: Thu, 6 Feb 2025 10:46:32 -0800 Subject: [PATCH 06/10] Adding not null validations --- .../awssdk/services/cloudfront/CloudFrontUtilities.java | 6 ------ .../services/cloudfront/internal/utils/SigningUtils.java | 7 ++++--- .../services/cloudfront/model/CustomSignerRequest.java | 3 ++- .../services/cloudfront/CloudFrontUtilitiesTest.java | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index 2a28e1084930..1d9ee75d2912 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -254,12 +254,6 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer + NullPointerException exception = assertThrows(NullPointerException.class, () -> cloudFrontUtilities.getSignedUrlWithCustomPolicy(r -> r .resourceUrl(RESOURCE_URL) .privateKey(keyPair.getPrivate()) From 766c3cdf31643c60280862d6c2b2ed97c7671e8c Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Thu, 6 Feb 2025 13:26:33 -0800 Subject: [PATCH 07/10] Changing resources name for intg test suite recreation --- .../services/cloudfront/CloudFrontUtilitiesIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java index b57b184d0332..785f68cf284b 100644 --- a/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java +++ b/services/cloudfront/src/test/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilitiesIntegrationTest.java @@ -75,7 +75,7 @@ public class CloudFrontUtilitiesIntegrationTest extends IntegrationTestBase { private static final Base64.Encoder ENCODER = Base64.getEncoder(); - private static final String RESOURCE_PREFIX = "do-not-delete-cf-test-"; + private static final String RESOURCE_PREFIX = "do-not-delete-cf-test-v2"; private static final String CALLER_REFERENCE = UUID.randomUUID().toString(); private static final String S3_OBJECT_KEY = "s3ObjectKey"; private static final String S3_OBJECT_KEY_ON_SUB_PATH = "foo/specific-file"; From 95dd934a53c49b4e9e014751351827e96acdeb7c Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Tue, 11 Feb 2025 12:40:59 -0800 Subject: [PATCH 08/10] Renaming policyResource, adding a test --- .../cloudfront/CloudFrontUtilities.java | 16 ++++++-------- .../cloudfront/model/CustomSignerRequest.java | 22 +++++++++---------- .../CloudFrontUtilitiesIntegrationTest.java | 6 ++--- .../cloudfront/CloudFrontUtilitiesTest.java | 9 +++++++- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index 1d9ee75d2912..853adb70f220 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -33,6 +33,7 @@ import software.amazon.awssdk.services.cloudfront.model.CannedSignerRequest; import software.amazon.awssdk.services.cloudfront.model.CustomSignerRequest; import software.amazon.awssdk.services.cloudfront.url.SignedUrl; +import software.amazon.awssdk.utils.StringUtils; /** * @@ -210,16 +211,13 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer - * Note: If you require a wildcard or a different resource path in the policy than the actual {@code resourceUrl}, - * use the optional {@code policyResource} field in {@link CustomSignerRequest}. * For more information, see Creating a signed URL using a custom policy. * * @param request * A {@link CustomSignerRequest} configured with the following values: - * resourceUrl, privateKey, keyPairId, expirationDate, activeDate (optional), ipRange (optional), policyResource + * resourceUrl, privateKey, keyPairId, expirationDate, activeDate (optional), ipRange (optional), resourceUrlPattern * (optional) * @return A signed URL that will permit access to distribution and S3 * objects as specified in the policy document. @@ -237,7 +235,7 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer CustomSignerRequest.builder().build()) + .withMessageContaining("resourceUrl must not be null"); + } } From b10ef40a89d6f9e7f3dbecede3bb17ccff337136 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Fri, 14 Feb 2025 11:25:36 -0800 Subject: [PATCH 09/10] Adding parameterized test --- .../cloudfront/CloudFrontUtilities.java | 6 +-- .../cloudfront/CloudFrontUtilitiesTest.java | 39 ++++++++++++++----- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index 853adb70f220..b39b0c27a8cb 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -253,9 +253,9 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer provideUrlPatternsAndExpectedResources() { + return Stream.of( + Arguments.of("*", "*"), + Arguments.of("https://d1234.cloudfront.net/*", "https://d1234.cloudfront.net/*"), + Arguments.of("https://d1234.cloudfront.net/images/*", "https://d1234.cloudfront.net/images/*"), + Arguments.of("https://d1234.cloudfront.net/*/photo.jpg", "https://d1234.cloudfront.net/*/photo.jpg"), + Arguments.of("https://d1234.cloudfront.net/images/photo+with-plus.jpg", + "https://d1234.cloudfront.net/images/photo+with-plus.jpg"), + Arguments.of("https://d1234.cloudfront.net/images/photo?param=value", + "https://d1234.cloudfront.net/images/photo?param=value"), + Arguments.of("https://d1234.cloudfront.net/images/photo-ümlaut.jpg", + "https://d1234.cloudfront.net/images/photo-ümlaut.jpg")); + } + @Test void customSignerRequest_nullResourceUrlShouldThrow(){ assertThatNullPointerException().isThrownBy(() -> CustomSignerRequest.builder().build()) From a9c575567ec354929c830d425d07e69371f68e59 Mon Sep 17 00:00:00 2001 From: Ran Vaknin Date: Mon, 17 Feb 2025 10:01:07 -0800 Subject: [PATCH 10/10] Fix checkstyle --- .../awssdk/services/cloudfront/CloudFrontUtilities.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java index b39b0c27a8cb..0c0e0b493528 100644 --- a/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java +++ b/services/cloudfront/src/main/java/software/amazon/awssdk/services/cloudfront/CloudFrontUtilities.java @@ -217,8 +217,13 @@ public SignedUrl getSignedUrlWithCustomPolicy(Consumer