From cf92b6fd80042cfc7fc73356779fd3c106449d5b Mon Sep 17 00:00:00 2001 From: Jon Austin <62040422+jonaustin09@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:01:16 -0500 Subject: [PATCH] Fix/azure copy object (#382) * fix: Added destination bucket acl check and metadata comparision for CopyObject action in azure backend --------- Co-authored-by: Ben McClelland --- backend/azure/azure.go | 44 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/backend/azure/azure.go b/backend/azure/azure.go index ce12ccc..f484ab0 100644 --- a/backend/azure/azure.go +++ b/backend/azure/azure.go @@ -399,16 +399,40 @@ func (az *Azure) DeleteObjects(ctx context.Context, input *s3.DeleteObjectsInput } func (az *Azure) CopyObject(ctx context.Context, input *s3.CopyObjectInput) (*s3.CopyObjectOutput, error) { - client, err := az.getBlobClient(*input.Bucket, *input.Key) + containerClient, err := az.getContainerClient(*input.Bucket) if err != nil { return nil, err } + res, err := containerClient.GetProperties(ctx, &container.GetPropertiesOptions{}) + if err != nil { + return nil, azureErrToS3Err(err) + } + + dstContainerAcl, err := getAclFromMetadata(res.Metadata, aclKeyCapital) + if err != nil { + return nil, err + } + + err = auth.VerifyACL(*dstContainerAcl, *input.ExpectedBucketOwner, types.PermissionWrite, false) + if err != nil { + return nil, err + } + + if strings.Join([]string{*input.Bucket, *input.Key}, "/") == *input.CopySource && isMetaSame(res.Metadata, input.Metadata) { + return nil, s3err.GetAPIError(s3err.ErrInvalidCopyDest) + } + tags, err := parseTags(input.Tagging) if err != nil { return nil, err } + client, err := az.getBlobClient(*input.Bucket, *input.Key) + if err != nil { + return nil, err + } + resp, err := client.CopyFromURL(ctx, az.serviceURL+"/"+*input.CopySource, &blob.CopyFromURLOptions{ BlobTags: tags, Metadata: parseMetadata(input.Metadata), @@ -942,3 +966,21 @@ func getAclFromMetadata(meta map[string]*string, key aclKey) (*auth.ACL, error) return &acl, nil } + +func isMetaSame(azMeta map[string]*string, awsMeta map[string]string) bool { + if len(azMeta) != len(awsMeta)+1 { + return false + } + + for key, val := range azMeta { + if key == string(aclKeyCapital) || key == string(aclKeyLower) { + continue + } + awsVal, ok := awsMeta[key] + if !ok || awsVal != *val { + return false + } + } + + return true +}