fix(s3api): correct wildcard matching (#8052)
* fix(s3api): correct wildcard matching * chore(tests): add multi-slash test case in ref. to cases provided here https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html\#reference_policies_elements_resource_wildcards * fix: gemini suggestions
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/credential"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
|
||||
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -159,6 +160,102 @@ func TestCanDo(t *testing.T) {
|
||||
assert.Equal(t, true, ident7.canDo(ACTION_DELETE_BUCKET, "bucket1", ""))
|
||||
}
|
||||
|
||||
func TestMatchWildcardPattern(t *testing.T) {
|
||||
tests := []struct {
|
||||
pattern string
|
||||
target string
|
||||
match bool
|
||||
}{
|
||||
// Basic * wildcard tests
|
||||
{"Bucket/*", "Bucket/a/b", true},
|
||||
{"Bucket/*", "x/Bucket/a", false},
|
||||
{"Bucket/*/admin", "Bucket/x/admin", true},
|
||||
{"Bucket/*/admin", "Bucket/x/y/admin", true},
|
||||
{"Bucket/*/admin", "Bucket////x////uwu////y////admin", true},
|
||||
{"abc*def", "abcXYZdef", true},
|
||||
{"abc*def", "abcXYZdefZZ", false},
|
||||
{"syr/*", "syr/a/b", true},
|
||||
|
||||
// ? wildcard tests (matches exactly one character)
|
||||
{"ab?d", "abcd", true},
|
||||
{"ab?d", "abXd", true},
|
||||
{"ab?d", "abd", false}, // ? must match exactly one character
|
||||
{"ab?d", "abcXd", false}, // ? matches only one character
|
||||
{"a?c", "abc", true},
|
||||
{"a?c", "aXc", true},
|
||||
{"a?c", "ac", false},
|
||||
{"???", "abc", true},
|
||||
{"???", "ab", false},
|
||||
{"???", "abcd", false},
|
||||
|
||||
// Combined * and ? wildcards
|
||||
{"a*?", "ab", true}, // * matches empty, ? matches 'b'
|
||||
{"a*?", "abc", true}, // * matches 'b', ? matches 'c'
|
||||
{"a*?", "a", false}, // ? must match something
|
||||
{"a?*", "ab", true}, // ? matches 'b', * matches empty
|
||||
{"a?*", "abc", true}, // ? matches 'b', * matches 'c'
|
||||
{"a?*b", "aXb", true}, // ? matches 'X', * matches empty
|
||||
{"a?*b", "aXYZb", true},
|
||||
{"*?*", "a", true},
|
||||
{"*?*", "", false}, // ? requires at least one character
|
||||
|
||||
// Edge cases: * matches empty string
|
||||
{"a*b", "ab", true}, // * matches empty string
|
||||
{"a**b", "ab", true}, // multiple stars match empty
|
||||
{"a**b", "axb", true}, // multiple stars match 'x'
|
||||
{"a**b", "axyb", true},
|
||||
{"*", "", true},
|
||||
{"*", "anything", true},
|
||||
{"**", "", true},
|
||||
{"**", "anything", true},
|
||||
|
||||
// Edge cases: empty strings
|
||||
{"", "", true},
|
||||
{"a", "", false},
|
||||
{"", "a", false},
|
||||
|
||||
// Trailing * matches empty
|
||||
{"a*", "a", true},
|
||||
{"a*", "abc", true},
|
||||
{"abc*", "abc", true},
|
||||
{"abc*", "abcdef", true},
|
||||
|
||||
// Leading * matches empty
|
||||
{"*a", "a", true},
|
||||
{"*a", "XXXa", true},
|
||||
{"*abc", "abc", true},
|
||||
{"*abc", "XXXabc", true},
|
||||
|
||||
// Multiple wildcards
|
||||
{"*a*", "a", true},
|
||||
{"*a*", "Xa", true},
|
||||
{"*a*", "aX", true},
|
||||
{"*a*", "XaX", true},
|
||||
{"*a*b*", "ab", true},
|
||||
{"*a*b*", "XaYbZ", true},
|
||||
|
||||
// Exact match (no wildcards)
|
||||
{"exact", "exact", true},
|
||||
{"exact", "notexact", false},
|
||||
{"exact", "exactnot", false},
|
||||
|
||||
// S3-style action patterns
|
||||
{"Read:bucket*", "Read:bucket-test", true},
|
||||
{"Read:bucket*", "Read:bucket", true},
|
||||
{"Write:bucket/path/*", "Write:bucket/path/file.txt", true},
|
||||
{"Admin:*", "Admin:anything", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.pattern+"_"+tt.target, func(t *testing.T) {
|
||||
result := policy_engine.MatchesWildcard(tt.pattern, tt.target)
|
||||
if result != tt.match {
|
||||
t.Errorf("policy_engine.MatchesWildcard(%q, %q) = %v, want %v", tt.pattern, tt.target, result, tt.match)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type LoadS3ApiConfigurationTestCase struct {
|
||||
pbAccount *iam_pb.Account
|
||||
pbIdent *iam_pb.Identity
|
||||
|
||||
Reference in New Issue
Block a user