mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-13 17:48:29 +02:00
s3: read bucket owner and crtime from the entry-free bucket config
The owner index read the raw filer entry off BucketConfig, which no longer carries one. Cache Crtime alongside IdentityId, and pass the owner id rather than the entry through the ListBuckets visibility checks so the scan and granted-bucket paths share one implementation.
This commit is contained in:
1 parent
17af32f3ff
commit
98e49d2d42
3 files changed
+19
-28
No files matched your search
@@ -38,6 +38,7 @@ type BucketConfig struct {
|
|||||||
ACL []byte
|
ACL []byte
|
||||||
Owner string
|
Owner string
|
||||||
IdentityId string // identity that created the bucket
|
IdentityId string // identity that created the bucket
|
||||||
|
Crtime int64 // bucket creation time, unix seconds
|
||||||
IsPublicRead bool // Cached flag to avoid JSON parsing on every request
|
IsPublicRead bool // Cached flag to avoid JSON parsing on every request
|
||||||
CORS *cors.CORSConfiguration
|
CORS *cors.CORSConfiguration
|
||||||
ObjectLockConfig *ObjectLockConfiguration // Cached parsed Object Lock configuration
|
ObjectLockConfig *ObjectLockConfiguration // Cached parsed Object Lock configuration
|
||||||
@@ -404,6 +405,10 @@ func (s3a *S3ApiServer) newBucketConfigFromEntry(bucket string, entry *filer_pb.
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if entry.Attributes != nil {
|
||||||
|
config.Crtime = entry.Attributes.Crtime
|
||||||
|
}
|
||||||
|
|
||||||
if entry.Extended != nil {
|
if entry.Extended != nil {
|
||||||
if versioning, exists := entry.Extended[s3_constants.ExtVersioningKey]; exists {
|
if versioning, exists := entry.Extended[s3_constants.ExtVersioningKey]; exists {
|
||||||
config.Versioning = string(versioning)
|
config.Versioning = string(versioning)
|
||||||
|
|||||||
@@ -144,11 +144,11 @@ func decodeContinuationToken(token string) (string, error) {
|
|||||||
|
|
||||||
// bucketVisibleToIdentity reports whether ListBuckets should include the bucket:
|
// bucketVisibleToIdentity reports whether ListBuckets should include the bucket:
|
||||||
// the identity owns it or has explicit permission to list it.
|
// the identity owns it or has explicit permission to list it.
|
||||||
func (s3a *S3ApiServer) bucketVisibleToIdentity(r *http.Request, entry *filer_pb.Entry, identity *Identity) bool {
|
func (s3a *S3ApiServer) bucketVisibleToIdentity(r *http.Request, bucket, owner string, identity *Identity) bool {
|
||||||
if isBucketOwnedByIdentity(entry, identity) {
|
if isBucketOwnedByIdentity(owner, identity) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return s3a.iam.VerifyActionPermission(r, identity, s3_constants.ACTION_LIST, entry.Name, "") == s3err.ErrNone
|
return s3a.iam.VerifyActionPermission(r, identity, s3_constants.ACTION_LIST, bucket, "") == s3err.ErrNone
|
||||||
}
|
}
|
||||||
|
|
||||||
// scanVisibleBuckets pages through /buckets and collects up to maxBuckets
|
// scanVisibleBuckets pages through /buckets and collects up to maxBuckets
|
||||||
@@ -169,7 +169,7 @@ func (s3a *S3ApiServer) scanVisibleBuckets(r *http.Request, identity *Identity,
|
|||||||
if !entry.IsDirectory || strings.HasPrefix(entry.Name, ".") {
|
if !entry.IsDirectory || strings.HasPrefix(entry.Name, ".") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !s3a.bucketVisibleToIdentity(r, entry, identity) {
|
if !s3a.bucketVisibleToIdentity(r, entry.Name, bucketEntryOwner(entry), identity) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
buckets = append(buckets, ListAllMyBucketsEntry{
|
buckets = append(buckets, ListAllMyBucketsEntry{
|
||||||
@@ -191,18 +191,14 @@ func (s3a *S3ApiServer) scanVisibleBuckets(r *http.Request, identity *Identity,
|
|||||||
return buckets, nextToken, nil
|
return buckets, nextToken, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// isBucketOwnedByIdentity checks if a bucket entry is owned by the given identity.
|
// isBucketOwnedByIdentity checks if a bucket with the given owner id (its
|
||||||
// Returns true if the identity owns the bucket, false otherwise.
|
// AmzIdentityId metadata) is owned by the given identity.
|
||||||
//
|
//
|
||||||
// Ownership rules:
|
// Ownership rules:
|
||||||
// - Admin users: considered owners of all buckets
|
// - Admin users: considered owners of all buckets
|
||||||
// - Non-admin users: own buckets where AmzIdentityId matches identity.Name
|
// - Non-admin users: own buckets whose owner id matches identity.Name
|
||||||
// - Buckets without owner metadata are not owned by anyone (except admins)
|
// - Buckets without owner metadata are not owned by anyone (except admins)
|
||||||
func isBucketOwnedByIdentity(entry *filer_pb.Entry, identity *Identity) bool {
|
func isBucketOwnedByIdentity(owner string, identity *Identity) bool {
|
||||||
if !entry.IsDirectory {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if identity == nil {
|
if identity == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -214,17 +210,7 @@ func isBucketOwnedByIdentity(entry *filer_pb.Entry, identity *Identity) bool {
|
|||||||
|
|
||||||
// Non-admin users with no name cannot own buckets.
|
// Non-admin users with no name cannot own buckets.
|
||||||
// This prevents misconfigured identities from matching buckets with empty owner IDs.
|
// This prevents misconfigured identities from matching buckets with empty owner IDs.
|
||||||
if identity.Name == "" {
|
return identity.Name != "" && identity.Name == owner
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check ownership via AmzIdentityId metadata
|
|
||||||
id, ok := entry.Extended[s3_constants.AmzIdentityId]
|
|
||||||
if !ok || string(id) != identity.Name {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -416,10 +402,10 @@ func (s3a *S3ApiServer) healBucketOwnerIndex(bucket, identityId string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
config, errCode := s3a.getBucketConfig(bucket)
|
config, errCode := s3a.getBucketConfig(bucket)
|
||||||
if errCode != s3err.ErrNone || bucketEntryOwner(config.Entry) != identityId {
|
if errCode != s3err.ErrNone || config.IdentityId != identityId {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err := s3a.addBucketToOwnerIndex(identityId, bucket, config.Entry.Attributes.Crtime); err != nil {
|
if err := s3a.addBucketToOwnerIndex(identityId, bucket, config.Crtime); err != nil {
|
||||||
glog.V(1).Infof("owner index heal %s/%s: %v", identityId, bucket, err)
|
glog.V(1).Infof("owner index heal %s/%s: %v", identityId, bucket, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -483,7 +469,7 @@ func (s3a *S3ApiServer) DeleteBucketHandler(w http.ResponseWriter, r *http.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if owner := bucketEntryOwner(bucketConfig.Entry); owner != "" {
|
if owner := bucketConfig.IdentityId; owner != "" {
|
||||||
if err := s3a.removeBucketFromOwnerIndex(owner, bucket); err != nil {
|
if err := s3a.removeBucketFromOwnerIndex(owner, bucket); err != nil {
|
||||||
glog.Warningf("DeleteBucketHandler: owner index remove %s/%s: %v", owner, bucket, err)
|
glog.Warningf("DeleteBucketHandler: owner index remove %s/%s: %v", owner, bucket, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,12 +166,12 @@ func (s3a *S3ApiServer) resolveGrantedBuckets(r *http.Request, identity *Identit
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !s3a.bucketVisibleToIdentity(r, config.Entry, identity) {
|
if !s3a.bucketVisibleToIdentity(r, name, config.IdentityId, identity) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
granted = append(granted, ListAllMyBucketsEntry{
|
granted = append(granted, ListAllMyBucketsEntry{
|
||||||
Name: name,
|
Name: name,
|
||||||
CreationDate: time.Unix(config.Entry.Attributes.Crtime, 0).UTC(),
|
CreationDate: time.Unix(config.Crtime, 0).UTC(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return granted
|
return granted
|
||||||
|
|||||||
Reference in new issue
Block a user