s3tables: further refinements to filer operations and utilities
- Add multi-segment namespace support to ARN parsing - Refactor permission checking to use map lookup - Wrap lookup errors with ErrNotFound in filer operations - Standardize splitPath to use path package
This commit is contained in:
@@ -82,6 +82,10 @@ func (h *S3TablesHandler) getExtendedAttribute(ctx context.Context, client filer
|
|||||||
return nil, fmt.Errorf("%w: %s", ErrNotFound, path)
|
return nil, fmt.Errorf("%w: %s", ErrNotFound, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.Entry.Extended == nil {
|
||||||
|
return nil, fmt.Errorf("%w: %s", ErrAttributeNotFound, key)
|
||||||
|
}
|
||||||
|
|
||||||
data, ok := resp.Entry.Extended[key]
|
data, ok := resp.Entry.Extended[key]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("%w: %s", ErrAttributeNotFound, key)
|
return nil, fmt.Errorf("%w: %s", ErrAttributeNotFound, key)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package s3tables
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/seaweedfs/seaweedfs/weed/iam/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Permission represents a specific action permission
|
// Permission represents a specific action permission
|
||||||
@@ -80,6 +82,11 @@ var OperationPermissions = map[string]Permission{
|
|||||||
|
|
||||||
// CheckPermission checks if a principal has permission to perform an operation
|
// CheckPermission checks if a principal has permission to perform an operation
|
||||||
func CheckPermission(operation, principal, owner string) bool {
|
func CheckPermission(operation, principal, owner string) bool {
|
||||||
|
// Deny access if identities are empty
|
||||||
|
if principal == "" || owner == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Owner always has permission
|
// Owner always has permission
|
||||||
if principal == owner {
|
if principal == owner {
|
||||||
return true
|
return true
|
||||||
@@ -164,6 +171,14 @@ func CanManageTags(principal, owner string) bool {
|
|||||||
// ExtractPrincipalFromContext extracts the principal (account ID) from request context
|
// ExtractPrincipalFromContext extracts the principal (account ID) from request context
|
||||||
// For now, this returns the owner/creator, but can be extended to parse from request headers/certs
|
// For now, this returns the owner/creator, but can be extended to parse from request headers/certs
|
||||||
func ExtractPrincipalFromContext(contextID string) string {
|
func ExtractPrincipalFromContext(contextID string) string {
|
||||||
|
// Try to parse as ARN first
|
||||||
|
if strings.HasPrefix(contextID, "arn:") {
|
||||||
|
info := utils.ParsePrincipalARN(contextID)
|
||||||
|
if info.RoleName != "" {
|
||||||
|
return info.RoleName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Extract from context, e.g., "user123" or "account-id"
|
// Extract from context, e.g., "user123" or "account-id"
|
||||||
// This is a simplified version - in production, this would parse AWS auth headers
|
// This is a simplified version - in production, this would parse AWS auth headers
|
||||||
if strings.Contains(contextID, ":") {
|
if strings.Contains(contextID, ":") {
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package s3tables
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -25,12 +25,20 @@ func parseBucketNameFromARN(arn string) (string, error) {
|
|||||||
// parseTableFromARN extracts bucket name, namespace, and table name from ARN
|
// parseTableFromARN extracts bucket name, namespace, and table name from ARN
|
||||||
// ARN format: arn:aws:s3tables:{region}:{account}:bucket/{bucket-name}/table/{namespace}/{table-name}
|
// ARN format: arn:aws:s3tables:{region}:{account}:bucket/{bucket-name}/table/{namespace}/{table-name}
|
||||||
func parseTableFromARN(arn string) (bucketName, namespace, tableName string, err error) {
|
func parseTableFromARN(arn string) (bucketName, namespace, tableName string, err error) {
|
||||||
pattern := regexp.MustCompile(`^arn:aws:s3tables:[^:]*:[^:]*:bucket/([a-z0-9_-]+)/table/([a-z0-9_]+)/([a-z0-9_]+)$`)
|
// Updated regex to capture multi-segment namespaces containing slashes
|
||||||
|
pattern := regexp.MustCompile(`^arn:aws:s3tables:[^:]*:[^:]*:bucket/([a-z0-9_-]+)/table/([^/]+(?:/[^/]+)*)/([a-z0-9_]+)$`)
|
||||||
matches := pattern.FindStringSubmatch(arn)
|
matches := pattern.FindStringSubmatch(arn)
|
||||||
if len(matches) != 4 {
|
if len(matches) != 4 {
|
||||||
return "", "", "", fmt.Errorf("invalid table ARN: %s", arn)
|
return "", "", "", fmt.Errorf("invalid table ARN: %s", arn)
|
||||||
}
|
}
|
||||||
return matches[1], matches[2], matches[3], nil
|
|
||||||
|
// URL decode the namespace
|
||||||
|
namespaceUnescaped, err := url.QueryUnescape(matches[2])
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", fmt.Errorf("invalid namespace encoding in ARN: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches[1], namespaceUnescaped, matches[3], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path helpers
|
// Path helpers
|
||||||
@@ -94,9 +102,9 @@ func generateVersionToken() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// splitPath splits a path into directory and name components using stdlib
|
// splitPath splits a path into directory and name components using stdlib
|
||||||
func splitPath(path string) (dir, name string) {
|
func splitPath(p string) (dir, name string) {
|
||||||
dir = filepath.Dir(path)
|
dir = path.Dir(p)
|
||||||
name = filepath.Base(path)
|
name = path.Base(p)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user