[
https://issues.apache.org/jira/browse/HDDS-17649?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Andy Huang reassigned HDDS-17649:
---------------------------------
Assignee: Andy Huang
> UploadPartCopy Does Not Enforce x-amz-copy-source-if-match and
> x-amz-copy-source-if-none-match Preconditions
> ------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-17649
> URL: https://issues.apache.org/jira/browse/HDDS-17649
> Project: Apache Ozone
> Issue Type: Bug
> Components: S3
> Reporter: Bablu Raul
> Assignee: Andy Huang
> Priority: Major
>
> The Ozone S3 Gateway does not correctly enforce the ETag-based conditional
> headers during the UploadPartCopy operation.
> When UploadPartCopy is executed with a non-matching ETag using
> {{{}x-amz-copy-source-if-match{}}}, the request succeeds and the part is
> copied instead of returning HTTP 412 (PreconditionFailed).
> Similarly, when {{x-amz-copy-source-if-none-match}} is supplied with an ETag
> matching the current source object, the request succeeds instead of returning
> HTTP 412 (PreconditionFailed).
> This behavior is inconsistent with CopyObject, which correctly enforces the
> source-side ETag conditions.
> The issue was also reproduced after overwriting the source object.
> UploadPartCopy using the old source ETag still succeeds and copies the
> updated source object's content.
> h2. Steps to Reproduce
> # Authenticate using Kerberos
> # Configure the S3 endpoint, credentials, and AWS CLI environment.
> # Create a bucket and upload a 6 MiB source object:
> {{export TS=$(date +%Y%m%d-%H%M%S)
> export BKT=cpif-$TS SRC=src-$TS DST=dst-$TS
> A s3api create-bucket --bucket "$BKT"
> head -c 6291456 /dev/urandom > /tmp/cpif_v1_$TS.bin
> A s3api put-object \
> --bucket "$BKT" \
> --key "$SRC" \
> --body /tmp/cpif_v1_$TS.bin
> export ETAG1=$(A s3api head-object \
> --bucket "$BKT" \
> --key "$SRC" \
> --query ETag --output text)
> export BAD='"00000000000000000000000000000000"'}}
> # Initiate a multipart upload:
> {{export UPID=$(A s3api create-multipart-upload \
> --bucket "$BKT" \
> --key "$DST" \
> --query UploadId --output text)}}
> # Execute UploadPartCopy with a non-matching If-Match ETag:
> {{A s3api upload-part-copy \
> --bucket "$BKT" \
> --key "$DST" \
> --upload-id "$UPID" \
> --part-number 1 \
> --copy-source "$BKT/$SRC" \
> --copy-source-if-match "$BAD"}}
> The request succeeds and returns CopyPartResult instead of PreconditionFailed.
> # Execute UploadPartCopy with If-None-Match using the current source
> object's ETag:
> {{A s3api upload-part-copy \
> --bucket "$BKT" \
> --key "$DST" \
> --upload-id "$UPID" \
> --part-number 2 \
> --copy-source "$BKT/$SRC" \
> --copy-source-if-none-match "$ETAG1"}}
> The request also succeeds, even though the supplied ETag matches the current
> source object.
> # Verify the control behavior by executing CopyObject with an invalid
> If-Match ETag:
> {{A s3api copy-object \
> --bucket "$BKT" \
> --key "ctl-$TS" \
> --copy-source "$BKT/$SRC" \
> --copy-source-if-match "$BAD"}}
> CopyObject correctly returns PreconditionFailed.
> # Verify that UploadPartCopy enforces the date-based condition by supplying
> an old date:
> {{A s3api upload-part-copy \
> --bucket "$BKT" \
> --key "$DST" \
> --upload-id "$UPID" \
> --part-number 3 \
> --copy-source "$BKT/$SRC" \
> --copy-source-if-unmodified-since "2000-01-01T00:00:00Z"}}
> The request correctly returns PreconditionFailed.
> # Overwrite the source object with new content and retrieve its updated ETag:
> {{head -c 6291456 /dev/urandom > /tmp/cpif_v2_$TS.bin
> A s3api put-object \
> --bucket "$BKT" \
> --key "$SRC" \
> --body /tmp/cpif_v2_$TS.bin
> export ETAG2=$(A s3api head-object \
> --bucket "$BKT" \
> --key "$SRC" \
> --query ETag --output text)
> echo "ETAG1=$ETAG1 ETAG2=$ETAG2"}}
> # Initiate another multipart upload and execute UploadPartCopy using the old
> ETag:
> {{export UP2=$(A s3api create-multipart-upload \
> --bucket "$BKT" \
> --key "stale-$TS" \
> --query UploadId --output text)
> export PET=$(A s3api upload-part-copy \
> --bucket "$BKT" \
> --key "stale-$TS" \
> --upload-id "$UP2" \
> --part-number 1 \
> --copy-source "$BKT/$SRC" \
> --copy-source-if-match "$ETAG1" \
> --query CopyPartResult.ETag \
> --output text)}}
> The request succeeds even though the source object's ETag has changed.
> # Complete the multipart upload and download the resulting object:
> {{A s3api complete-multipart-upload \
> --bucket "$BKT" \
> --key "stale-$TS" \
> --upload-id "$UP2" \
> --multipart-upload "\{\"Parts\":[{\"PartNumber\":1,\"ETag\":$PET}]}"
> A s3api get-object \
> --bucket "$BKT" \
> --key "stale-$TS" \
> /tmp/cpif_out_$TS.bin
> md5sum /tmp/cpif_v1_$TS.bin \
> /tmp/cpif_v2_$TS.bin \
> /tmp/cpif_out_$TS.bin}}
> h2. Actual Result
> * UploadPartCopy succeeds when {{x-amz-copy-source-if-match}} contains a
> non-matching ETag.
> * UploadPartCopy succeeds when {{x-amz-copy-source-if-none-match}} contains
> an ETag matching the current source object.
> * UploadPartCopy succeeds with an old ETag after the source object has been
> overwritten.
> * The completed destination object contains the updated source object's
> content (V2), instead of rejecting the request based on the old ETag.
> * CopyObject correctly enforces the If-Match condition.
> * UploadPartCopy correctly enforces the If-Unmodified-Since condition.
> h2. Expected Result
> UploadPartCopy should enforce the source-side ETag conditional headers
> consistently with CopyObject.
> * If {{x-amz-copy-source-if-match}} does not match the source object's ETag,
> the request should fail with HTTP 412 (PreconditionFailed).
> * If {{x-amz-copy-source-if-none-match}} matches the source object's ETag,
> the request should fail with HTTP 412 (PreconditionFailed).
> * If the source object is overwritten after the client retrieves its ETag,
> UploadPartCopy using the old ETag should fail with HTTP 412
> (PreconditionFailed).
> * No part should be created when the source-side precondition fails.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]