This is an automated email from the ASF dual-hosted git repository.
ivandika pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new ae9c53cfba7 HDDS-13663. Validate Presigned DeleteObject (#9019)
ae9c53cfba7 is described below
commit ae9c53cfba7a449455e4c031b838d05e8689b969
Author: Hsu Han Wen <[email protected]>
AuthorDate: Fri Sep 12 11:46:12 2025 +0800
HDDS-13663. Validate Presigned DeleteObject (#9019)
---
.../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java | 34 +++++++++
.../ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java | 87 ++++++++++++++++++++++
2 files changed, 121 insertions(+)
diff --git
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
index eed72db3c13..54bdddf6e1c 100644
---
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
+++
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
@@ -1378,6 +1378,40 @@ private GeneratePresignedUrlRequest
createInitMPUPresignedUrlRequest(String buck
return initMPUPresignUrlRequest;
}
+ @Test
+ public void testPresignedUrlDelete() throws IOException {
+ final String bucketName = getBucketName();
+ final String keyName = getKeyName();
+ final String content = "bar";
+
+ s3Client.createBucket(bucketName);
+ try (InputStream is = new
ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8))) {
+ s3Client.putObject(bucketName, keyName, is, new ObjectMetadata());
+ }
+
+ // Set the presigned URL to expire after one hour.
+ Date expiration = Date.from(Instant.now().plusMillis(1000 * 60 * 60));
+
+ // Generate the presigned URL for DELETE
+ GeneratePresignedUrlRequest generatePresignedUrlRequest =
+ new GeneratePresignedUrlRequest(bucketName, keyName)
+ .withMethod(HttpMethod.DELETE)
+ .withExpiration(expiration);
+ URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
+
+ // Execute the DELETE request using HttpUrlConnection
+ URL presignedUrl = new URL(url.toExternalForm());
+ HttpURLConnection connection = (HttpURLConnection)
presignedUrl.openConnection();
+ connection.setRequestMethod("DELETE");
+ int responseCode = connection.getResponseCode();
+
+ // Verify the response code is 204 (No Content)
+ assertEquals(HttpURLConnection.HTTP_NO_CONTENT, responseCode);
+
+ // Verify the object is deleted
+ assertFalse(s3Client.doesObjectExist(bucketName, keyName));
+ }
+
/**
* Tests the functionality to create a snapshot of an Ozone bucket and then
read files
* from the snapshot directory using the S3 SDK.
diff --git
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
index ff54190d3f3..31f58c6d9a2 100644
---
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
+++
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
@@ -103,6 +103,7 @@
import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.Delete;
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest;
+import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectTaggingRequest;
import software.amazon.awssdk.services.s3.model.DeleteObjectsRequest;
import software.amazon.awssdk.services.s3.model.GetBucketAclRequest;
@@ -119,6 +120,7 @@
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Response;
import software.amazon.awssdk.services.s3.model.ListPartsRequest;
+import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
import software.amazon.awssdk.services.s3.model.ObjectIdentifier;
import software.amazon.awssdk.services.s3.model.PutBucketAclRequest;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
@@ -134,11 +136,13 @@
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import
software.amazon.awssdk.services.s3.presigner.model.CompleteMultipartUploadPresignRequest;
import
software.amazon.awssdk.services.s3.presigner.model.CreateMultipartUploadPresignRequest;
+import
software.amazon.awssdk.services.s3.presigner.model.DeleteObjectPresignRequest;
import
software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import
software.amazon.awssdk.services.s3.presigner.model.HeadBucketPresignRequest;
import
software.amazon.awssdk.services.s3.presigner.model.HeadObjectPresignRequest;
import
software.amazon.awssdk.services.s3.presigner.model.PresignedCompleteMultipartUploadRequest;
import
software.amazon.awssdk.services.s3.presigner.model.PresignedCreateMultipartUploadRequest;
+import
software.amazon.awssdk.services.s3.presigner.model.PresignedDeleteObjectRequest;
import
software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
import
software.amazon.awssdk.services.s3.presigner.model.PresignedHeadBucketRequest;
import
software.amazon.awssdk.services.s3.presigner.model.PresignedHeadObjectRequest;
@@ -1077,6 +1081,89 @@ private String
buildCompleteMultipartUploadXml(List<CompletedPart> parts) {
return xml.toString();
}
+ @Test
+ public void testPresignedUrlDelete() throws Exception {
+ final String bucketName = getBucketName();
+ final String keyName = getKeyName();
+ final String content = "bar";
+ s3Client.createBucket(b -> b.bucket(bucketName));
+
+ s3Client.putObject(b -> b
+ .bucket(bucketName)
+ .key(keyName),
+ RequestBody.fromString(content));
+
+ try (S3Presigner presigner = createS3Presigner()) {
+
+ DeleteObjectRequest objectRequest = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(keyName)
+ .build();
+
+ DeleteObjectPresignRequest presignRequest =
DeleteObjectPresignRequest.builder()
+ .signatureDuration(Duration.ofMinutes(10))
+ .deleteObjectRequest(objectRequest)
+ .build();
+
+ PresignedDeleteObjectRequest presignedRequest =
presigner.presignDeleteObject(presignRequest);
+
+ // use http url connection
+ HttpURLConnection connection = null;
+ try {
+ connection = (HttpURLConnection)
presignedRequest.url().openConnection();
+ connection.setRequestMethod("DELETE");
+
+ int responseCode = connection.getResponseCode();
+ assertEquals(204, responseCode, "DeleteObject presigned URL should
return 204 No Content");
+
+ //verify the object was deleted
+ assertThrows(NoSuchKeyException.class, () -> s3Client.getObject(b ->
b.bucket(bucketName).key(keyName)));
+ } finally {
+ if (connection != null) {
+ connection.disconnect();
+ }
+ }
+ }
+
+ // use SdkHttpClient
+ s3Client.putObject(b -> b
+ .bucket(bucketName)
+ .key(keyName),
+ RequestBody.fromString(content));
+
+ try (S3Presigner presigner = createS3Presigner();
+ SdkHttpClient sdkHttpClient = ApacheHttpClient.create()) {
+
+ DeleteObjectRequest objectRequest = DeleteObjectRequest.builder()
+ .bucket(bucketName)
+ .key(keyName)
+ .build();
+
+ DeleteObjectPresignRequest presignRequest =
DeleteObjectPresignRequest.builder()
+ .signatureDuration(Duration.ofMinutes(10))
+ .deleteObjectRequest(objectRequest)
+ .build();
+
+ PresignedDeleteObjectRequest presignedRequest =
presigner.presignDeleteObject(presignRequest);
+
+ SdkHttpRequest request = SdkHttpRequest.builder()
+ .method(SdkHttpMethod.DELETE)
+ .uri(presignedRequest.url().toURI())
+ .build();
+
+ HttpExecuteRequest executeRequest = HttpExecuteRequest.builder()
+ .request(request)
+ .build();
+
+ HttpExecuteResponse response =
sdkHttpClient.prepareRequest(executeRequest).call();
+ assertEquals(204, response.httpResponse().statusCode(),
+ "DeleteObject presigned URL should return 204 No Content via
SdkHttpClient");
+
+ //verify the object was deleted
+ assertThrows(NoSuchKeyException.class, () -> s3Client.getObject(b ->
b.bucket(bucketName).key(keyName)));
+ }
+ }
+
private S3Presigner createS3Presigner() {
return S3Presigner.builder()
// TODO: Find a way to retrieve the path style configuration from
S3Client instead
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]