s3api: persist ACLs on PutObject uploads (#11592)

* s3api: persist ACLs on PutObject uploads

Signed-off-by: zhaoyuchen <43179751+zhao-yc@users.noreply.github.com>

* s3api: fix PutObject ACL edge cases found in review

- Only enforce BucketOwnerEnforced when explicitly configured; buckets
  without a stored ownership control keep accepting upload ACLs
- Ignore ACL query parameters on SigV2 requests, which do not sign them
- Mirror signed-query ACL values into headers after authentication so
  grant parsing and resolveFileMode agree on presigned uploads
- Validate only caller-supplied grantees against the account registry;
  default grants now work for accounts outside the local registry
- Reject unknown grantee keys and accept comma-separated grantee lists
  without spaces in ParseCustomAclHeader
- Guard against identities without an account

* s3api: harden upload ACL parsing and authorization

Signed-off-by: zhaoyuchen <43179751+zhao-yc@users.noreply.github.com>

* s3api: evaluate upload ACL grantees individually in policies

A comma-joined grant header or a signed query parameter reached policy
conditions as one value, so a deny on a later grantee did not fire. Split
grant headers into per-grantee values for policy evaluation and share the
grantee pair parser with ParseCustomAclHeader.

* s3api: keep raw grant header values visible to policy conditions

Exact-match conditions written against the signed header value stopped
matching once grantees were split for evaluation. Preserve the original
wire values alongside the per-grantee values so deny policies fire on
either granularity.

* s3api: evaluate upload ACL grants as one canonical list in policies

Conditions on s3:x-amz-grant-* now see a single comma-separated canonical
grant list identical for a single line, repeated header lines, or a signed
query parameter. This keeps StringEquals allows and exact-list or
allowlist (StringNotEquals) denies accurate regardless of wire encoding.

* s3api: preserve upload ACL denies and align policy checks

Signed-off-by: zhaoyuchen <43179751+zhao-yc@users.noreply.github.com>

* s3api: retain upload owner grants and literal policy values

Signed-off-by: zhaoyuchen <43179751+zhao-yc@users.noreply.github.com>

---------

Signed-off-by: zhaoyuchen <43179751+zhao-yc@users.noreply.github.com>
Co-authored-by: Chris Lu <chris.lu@gmail.com>
This commit is contained in:
zhao-ycandChris Lu authored and GitHub committed 2026-10-05 09:13:19 +08:00
1 parent 9d1c24d80d
commit 483dd4b12e
15 files changed
+1266 -48

No files matched your search

+9 -1
View File
@@ -1778,6 +1778,13 @@ func (iam *IdentityAccessManagement) authRequestWithAuthType(r *http.Request, ac
}
bucket, object := s3_constants.GetBucketAndObject(r)
// Verify the original signature first, then evaluate policies against the
// effective PUT ACL, including signed query parameters hoisted by presigners.
originalRequest := r
r, s3Err = putObjectACLPolicyRequest(r, action, bucket, object)
if s3Err != s3err.ErrNone {
return identity, s3Err, reqAuthType
}
prefix := s3_constants.GetPrefix(r)
// For bucket listings, use prefix for permission checking if available:
@@ -1873,7 +1880,7 @@ func (iam *IdentityAccessManagement) authRequestWithAuthType(r *http.Request, ac
}
}
r.Header.Set(s3_constants.AmzAccountId, identity.Account.Id)
originalRequest.Header.Set(s3_constants.AmzAccountId, identity.Account.Id)
return identity, s3err.ErrNone, reqAuthType
@@ -2558,6 +2565,7 @@ func (iam *IdentityAccessManagement) evaluateAttachedIAMPolicies(r *http.Request
Conditions: conditions,
Claims: identity.Claims,
}
evalArgs.OriginalGrantConditions = policy_engine.OriginalGrantConditionsFromRequest(r)
// Evaluate user's own policies
for _, policyName := range identity.PolicyNames {