diff --git a/weed/s3api/s3api_bucket_handlers.go b/weed/s3api/s3api_bucket_handlers.go index b318ee306..f09b1af55 100644 --- a/weed/s3api/s3api_bucket_handlers.go +++ b/weed/s3api/s3api_bucket_handlers.go @@ -565,8 +565,17 @@ func (s3a *S3ApiServer) checkBucket(r *http.Request, bucket string) s3err.ErrorC return s3err.ErrNone } +// ErrAutoCreatePermissionDenied is returned when a user lacks permission to auto-create buckets +var ErrAutoCreatePermissionDenied = fmt.Errorf("permission denied - requires Admin permission") + // autoCreateBucket creates a bucket if it doesn't exist, setting the owner from the request context +// Only users with admin permissions are allowed to auto-create buckets func (s3a *S3ApiServer) autoCreateBucket(r *http.Request, bucket string) error { + // Check if user has admin permissions + if !s3a.isUserAdmin(r) { + return fmt.Errorf("auto-create bucket %s: %w", bucket, ErrAutoCreatePermissionDenied) + } + currentIdentityId := s3_constants.GetIdentityNameFromContext(r) fn := func(entry *filer_pb.Entry) { if currentIdentityId != "" { diff --git a/weed/s3api/s3api_object_handlers_multipart.go b/weed/s3api/s3api_object_handlers_multipart.go index eabd4fe7a..78f5ca853 100644 --- a/weed/s3api/s3api_object_handlers_multipart.go +++ b/weed/s3api/s3api_object_handlers_multipart.go @@ -35,10 +35,15 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http // Check if bucket exists, and create it if it doesn't (auto-create bucket) if err := s3a.checkBucket(r, bucket); err == s3err.ErrNoSuchBucket { - // Auto-create bucket if it doesn't exist + // Auto-create bucket if it doesn't exist (requires Admin permission) if mkdirErr := s3a.autoCreateBucket(r, bucket); mkdirErr != nil { - glog.Errorf("NewMultipartUploadHandler: %v", mkdirErr) - s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) + glog.Warningf("NewMultipartUploadHandler: %v", mkdirErr) + // Check if it's a permission error using errors.Is() + if errors.Is(mkdirErr, ErrAutoCreatePermissionDenied) { + s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) + } else { + s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) + } return } } else if err != s3err.ErrNone { diff --git a/weed/s3api/s3api_object_handlers_put.go b/weed/s3api/s3api_object_handlers_put.go index 0caf5d025..22e77e6b6 100644 --- a/weed/s3api/s3api_object_handlers_put.go +++ b/weed/s3api/s3api_object_handlers_put.go @@ -135,10 +135,15 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request) versioningState, err := s3a.getVersioningState(bucket) if err != nil { if errors.Is(err, filer_pb.ErrNotFound) { - // Auto-create bucket if it doesn't exist + // Auto-create bucket if it doesn't exist (requires Admin permission) if mkdirErr := s3a.autoCreateBucket(r, bucket); mkdirErr != nil { - glog.Errorf("PutObjectHandler: %v", mkdirErr) - s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) + glog.Warningf("PutObjectHandler: %v", mkdirErr) + // Check if it's a permission error using errors.Is() + if errors.Is(mkdirErr, ErrAutoCreatePermissionDenied) { + s3err.WriteErrorResponse(w, r, s3err.ErrAccessDenied) + } else { + s3err.WriteErrorResponse(w, r, s3err.ErrInternalError) + } return } // After creating the bucket, versioning state is empty (not configured)