From 43aebc10daf363a33ed0137747b24e788a8159af Mon Sep 17 00:00:00 2001 From: Chris Lu Date: Wed, 28 Jan 2026 13:59:24 -0800 Subject: [PATCH] s3tables: enforce strict resource ownership and implement result filtering for namespaces --- weed/s3api/s3tables/handler_namespace.go | 39 ++++++++++++------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/weed/s3api/s3tables/handler_namespace.go b/weed/s3api/s3tables/handler_namespace.go index 26c75a9f4..4dcbad742 100644 --- a/weed/s3api/s3tables/handler_namespace.go +++ b/weed/s3api/s3tables/handler_namespace.go @@ -65,11 +65,10 @@ func (h *S3TablesHandler) handleCreateNamespace(w http.ResponseWriter, r *http.R return err } - // Check permission - principal := h.getPrincipalFromRequest(r) - if !CanCreateNamespace(principal, bucketMetadata.OwnerAccountID) { - h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to create namespace") - return NewAuthError("CreateNamespace", principal, "not authorized to create namespace") + // Check ownership + if accountID := h.getAccountID(r); accountID != bucketMetadata.OwnerAccountID { + h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to create namespace in this bucket") + return fmt.Errorf("access denied") } namespacePath := getNamespacePath(bucketName, namespaceName) @@ -176,11 +175,10 @@ func (h *S3TablesHandler) handleGetNamespace(w http.ResponseWriter, r *http.Requ return err } - // Check permission - principal := h.getPrincipalFromRequest(r) - if !CanGetNamespace(principal, metadata.OwnerAccountID) { - h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to get namespace details") - return NewAuthError("GetNamespace", principal, "not authorized to get namespace details") + // Check ownership + if accountID := h.getAccountID(r); accountID != metadata.OwnerAccountID { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchNamespace, "namespace not found") + return fmt.Errorf("access denied") } resp := &GetNamespaceResponse{ @@ -241,10 +239,10 @@ func (h *S3TablesHandler) handleListNamespaces(w http.ResponseWriter, r *http.Re return err } - principal := h.getPrincipalFromRequest(r) - if !CanListNamespaces(principal, bucketMetadata.OwnerAccountID) { - h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to list namespaces") - return NewAuthError("ListNamespaces", principal, "not authorized to list namespaces") + accountID := h.getAccountID(r) + if accountID != bucketMetadata.OwnerAccountID { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchBucket, fmt.Sprintf("table bucket %s not found", bucketName)) + return fmt.Errorf("access denied") } var namespaces []NamespaceSummary @@ -308,6 +306,10 @@ func (h *S3TablesHandler) handleListNamespaces(w http.ResponseWriter, r *http.Re continue } + if metadata.OwnerAccountID != accountID { + continue + } + namespaces = append(namespaces, NamespaceSummary{ Namespace: metadata.Namespace, CreatedAt: metadata.CreatedAt, @@ -398,11 +400,10 @@ func (h *S3TablesHandler) handleDeleteNamespace(w http.ResponseWriter, r *http.R return err } - // Check permission - principal := h.getPrincipalFromRequest(r) - if !CanDeleteNamespace(principal, metadata.OwnerAccountID) { - h.writeError(w, http.StatusForbidden, ErrCodeAccessDenied, "not authorized to delete namespace") - return NewAuthError("DeleteNamespace", principal, "not authorized to delete namespace") + // Check ownership + if accountID := h.getAccountID(r); accountID != metadata.OwnerAccountID { + h.writeError(w, http.StatusNotFound, ErrCodeNoSuchNamespace, "namespace not found") + return fmt.Errorf("access denied") } // Check if namespace is empty