From dfb380d887dee0a8f40ba50b6ef6cb99e62a0f84 Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Tue, 9 Nov 2021 21:49:37 -0100 Subject: [PATCH] S3 - PutObject cant specify ACL and Grant (#4550) --- moto/s3/exceptions.py | 12 ++++++++++++ moto/s3/responses.py | 7 +++++-- tests/test_s3/test_s3_acl.py | 26 ++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/moto/s3/exceptions.py b/moto/s3/exceptions.py index aec003f0e..39047bf44 100644 --- a/moto/s3/exceptions.py +++ b/moto/s3/exceptions.py @@ -347,6 +347,18 @@ class S3InvalidTokenError(S3ClientError): ) +class S3AclAndGrantError(S3ClientError): + code = 400 + + def __init__(self, *args, **kwargs): + super(S3AclAndGrantError, self).__init__( + "InvalidRequest", + "Specifying both Canned ACLs and Header Grants is not allowed", + *args, + **kwargs, + ) + + class BucketInvalidTokenError(BucketError): code = 400 diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 2ddf56368..aaa0427ce 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -46,6 +46,7 @@ from .exceptions import ( IllegalLocationConstraintException, InvalidNotificationARN, InvalidNotificationEvent, + S3AclAndGrantError, InvalidObjectState, ObjectNotInActiveTierError, NoSystemTags, @@ -1730,8 +1731,6 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin): def _acl_from_headers(self, headers): canned_acl = headers.get("x-amz-acl", "") - if canned_acl: - return get_canned_acl(canned_acl) grants = [] for header, value in headers.items(): @@ -1758,6 +1757,10 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin): grantees.append(FakeGrantee(uri=value)) grants.append(FakeGrant(grantees, [permission])) + if canned_acl and grants: + raise S3AclAndGrantError() + if canned_acl: + return get_canned_acl(canned_acl) if grants: return FakeAcl(grants) else: diff --git a/tests/test_s3/test_s3_acl.py b/tests/test_s3/test_s3_acl.py index d01d86c20..a32568098 100644 --- a/tests/test_s3/test_s3_acl.py +++ b/tests/test_s3/test_s3_acl.py @@ -326,3 +326,29 @@ def test_acl_setting_via_headers_boto3(): "Permission": "READ", } ) + + +@mock_s3 +def test_raise_exception_for_grant_and_acl(): + client = boto3.client("s3") + s3 = boto3.resource("s3") + bucket_name = "bucketname" + client.create_bucket(Bucket=bucket_name) + bucket = s3.Bucket(bucket_name) + acl = client.get_bucket_acl(Bucket=bucket_name) + acl_grantee_id = acl["Owner"]["ID"] + + # This should raise an exception or provide some error message, but runs without exception instead. + with pytest.raises(ClientError) as exc: + bucket.put_object( + ACL="bucket-owner-full-control", + Body="example-file-path", + Key="example-key", + ContentType="text/plain", + GrantFullControl=f'id="{acl_grantee_id}"', + ) + err = exc.value.response["Error"] + err["Code"].should.equal("InvalidRequest") + err["Message"].should.equal( + "Specifying both Canned ACLs and Header Grants is not allowed" + )