Files
seaweedfs/weed/s3api/s3api_acp.go
T
Jay Hemnanianduser.email 9059cc2a07 s3: allow PutObjectAcl when auth is off (#12155)
* s3: allow PutObjectAcl when auth is off

* s3: ownerless objects claim the admin account when auth is off

An object written through the filer carries no owner metadata, so
objectOwner fell back to an empty account id and ExtractAcl rejected the
canned ACL's canonical grantee. Extend TestPutObjectAclWithoutAuth to
cover the ownerless case.

* s3: GetObjectAcl reports the admin owner for ownerless objects when auth is off

The same empty-owner fallback produced an ACL response with a blank
Owner ID and a blank canonical grantee.

* s3: ignore the client-supplied account id when auth is off

Auth does not strip AmzAccountId on the iam-disabled path, so the
ownerless fallback could persist a forged owner. requestAccountId
substitutes the admin account, matching the idiom already used in the
upload ACL path.

---------

Co-authored-by: user.email <chrislusf@users.noreply.github.com>
2026-10-28 08:07:36 -07:00

47 lines
1.3 KiB
Go

package s3api
import (
"net/http"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
)
func getAccountId(r *http.Request) string {
id := r.Header.Get(s3_constants.AmzAccountId)
if len(id) == 0 {
return AccountAnonymous.Id
} else {
return id
}
}
// requestAccountId returns the authenticated caller's account; with auth off
// the header is client-supplied, so the admin account stands in instead.
func (s3a *S3ApiServer) requestAccountId(r *http.Request) string {
if s3a.iam != nil && !s3a.iam.isEnabled() {
return AccountAdmin.Id
}
return r.Header.Get(s3_constants.AmzAccountId)
}
func (s3a *S3ApiServer) checkAccessByOwnership(r *http.Request, bucket string) s3err.ErrorCode {
metadata, errCode := s3a.bucketRegistry.GetBucketMetadata(bucket)
if errCode != s3err.ErrNone {
return errCode
}
// Without auth there is no owner to compare against.
if s3a.iam != nil && !s3a.iam.isEnabled() {
return s3err.ErrNone
}
// Admin by capability, not account id: account-less identities share the "admin" id.
if s3a.isUserAdmin(r) {
return s3err.ErrNone
}
accountId := getAccountId(r)
if metadata.Owner != nil && metadata.Owner.ID != nil && accountId == *metadata.Owner.ID {
return s3err.ErrNone
}
return s3err.ErrAccessDenied
}