S3: list owned buckets (#7519)

* list owned buckets

* simplify

* add unit tests

* no-owner buckets

* set identity id

* fallback to request header if iam is not enabled

* refactor to test

* fix comparing

* fix security vulnerability

* Update s3api_bucket_handlers.go

* Update s3api_bucket_handlers.go

* Update s3api_bucket_handlers.go
This commit is contained in:
Chris Lu
2025-11-21 11:37:43 -08:00
committed by GitHub
parent 64dcbbb25b
commit a9fefcd22c
2 changed files with 467 additions and 1 deletions

View File

@@ -59,11 +59,21 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
return
}
identityId := r.Header.Get(s3_constants.AmzIdentityId)
identityId := ""
if identity != nil {
identityId = identity.Name
}
// Note: For unauthenticated requests, identityId remains empty.
// We never read from request headers to prevent reflecting unvalidated user input.
var listBuckets ListAllMyBucketsList
for _, entry := range entries {
if entry.IsDirectory {
// Check ownership: only show buckets owned by this user (unless admin)
if !isBucketVisibleToIdentity(entry, identity) {
continue
}
// Check permissions for each bucket
if identity != nil {
// For JWT-authenticated users, use IAM authorization
@@ -99,6 +109,47 @@ func (s3a *S3ApiServer) ListBucketsHandler(w http.ResponseWriter, r *http.Reques
writeSuccessResponseXML(w, r, response)
}
// isBucketVisibleToIdentity checks if a bucket entry should be visible to the given identity
// based on ownership rules. Returns true if the bucket should be visible, false otherwise.
//
// Visibility rules:
// - Unauthenticated requests (identity == nil): no buckets visible
// - Admin users: all buckets visible
// - Non-admin users: only buckets they own (matching identity.Name) are visible
// - Buckets without owner metadata are hidden from non-admin users
func isBucketVisibleToIdentity(entry *filer_pb.Entry, identity *Identity) bool {
if !entry.IsDirectory {
return false
}
// Unauthenticated users should not see any buckets (standard S3 behavior)
if identity == nil {
return false
}
// Admin users bypass ownership check
if identity.isAdmin() {
return true
}
// Non-admin users with no name cannot own or see buckets.
// This prevents misconfigured identities from matching buckets with empty owner IDs.
if identity.Name == "" {
return false
}
// Non-admin users: check ownership
// Use the authenticated identity value directly (cannot be spoofed)
id, ok := entry.Extended[s3_constants.AmzIdentityId]
// Skip buckets that are not owned by the current user.
// Buckets without an owner are also skipped.
if !ok || string(id) != identity.Name {
return false
}
return true
}
func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
// collect parameters