mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-07 23:07:48 +02:00
* 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>
47 lines
1.6 KiB
Go
47 lines
1.6 KiB
Go
package policy_engine
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
)
|
|
|
|
// originalGrantConditionsKey prevents clients from forging original grant values through request headers.
|
|
type originalGrantConditionsKey struct{}
|
|
|
|
// isGrantConditionKey restricts original-value checks to the five upload grant condition keys.
|
|
func isGrantConditionKey(key string) bool {
|
|
switch key {
|
|
case "s3:x-amz-grant-read", "s3:x-amz-grant-write", "s3:x-amz-grant-read-acp", "s3:x-amz-grant-write-acp", "s3:x-amz-grant-full-control":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// cloneGrantConditions isolates inputs and results so later mutations cannot change the original complete grant representation.
|
|
func cloneGrantConditions(values map[string][]string) map[string][]string {
|
|
if len(values) == 0 {
|
|
return nil
|
|
}
|
|
cloned := make(map[string][]string, len(values))
|
|
for key, grants := range values {
|
|
if isGrantConditionKey(key) {
|
|
cloned[key] = append([]string(nil), grants...)
|
|
}
|
|
}
|
|
return cloned
|
|
}
|
|
|
|
// WithOriginalGrantConditions saves the complete list before upload normalization to supplement explicit deny checks only.
|
|
func WithOriginalGrantConditions(r *http.Request, values map[string][]string) *http.Request {
|
|
return r.WithContext(context.WithValue(r.Context(), originalGrantConditionsKey{}, cloneGrantConditions(values)))
|
|
}
|
|
|
|
// OriginalGrantConditionsFromRequest reads the internal snapshot; other operations have no such context.
|
|
func OriginalGrantConditionsFromRequest(r *http.Request) map[string][]string {
|
|
if r == nil {
|
|
return nil
|
|
}
|
|
values, _ := r.Context().Value(originalGrantConditionsKey{}).(map[string][]string)
|
|
return cloneGrantConditions(values)
|
|
}
|