openapi: Fix logic for labeling unauthenticated/sudo paths (#19600)
This commit is contained in:
parent
1fe1c756ab
commit
4d10063cbd
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:bug
|
||||||
|
openapi: Fix logic for labeling unauthenticated/sudo paths.
|
||||||
|
```
|
|
@ -547,14 +547,55 @@ func constructRequestResponseName(path, prefix, suffix string) string {
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specialPathMatch checks whether the given path matches one of the special
|
||||||
|
// paths, taking into account * and + wildcards (e.g. foo/+/bar/*)
|
||||||
func specialPathMatch(path string, specialPaths []string) bool {
|
func specialPathMatch(path string, specialPaths []string) bool {
|
||||||
// Test for exact or prefix match of special paths.
|
// pathMatchesByParts determines if the path matches the special path's
|
||||||
|
// pattern, accounting for the '+' and '*' wildcards
|
||||||
|
pathMatchesByParts := func(pathParts []string, specialPathParts []string) bool {
|
||||||
|
if len(pathParts) < len(specialPathParts) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := 0; i < len(specialPathParts); i++ {
|
||||||
|
var (
|
||||||
|
part = pathParts[i]
|
||||||
|
pattern = specialPathParts[i]
|
||||||
|
)
|
||||||
|
if pattern == "+" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if pattern == "*" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(pattern, "*") && strings.HasPrefix(part, pattern[0:len(pattern)-1]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if pattern != part {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len(pathParts) == len(specialPathParts)
|
||||||
|
}
|
||||||
|
|
||||||
|
pathParts := strings.Split(path, "/")
|
||||||
|
|
||||||
for _, sp := range specialPaths {
|
for _, sp := range specialPaths {
|
||||||
if sp == path ||
|
// exact match
|
||||||
(strings.HasSuffix(sp, "*") && strings.HasPrefix(path, sp[0:len(sp)-1])) {
|
if sp == path {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// match *
|
||||||
|
if strings.HasSuffix(sp, "*") && strings.HasPrefix(path, sp[0:len(sp)-1]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// match +
|
||||||
|
if strings.Contains(sp, "+") && pathMatchesByParts(pathParts, strings.Split(sp, "/")) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -226,42 +226,123 @@ func TestOpenAPI_SplitFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenAPI_SpecialPaths(t *testing.T) {
|
func TestOpenAPI_SpecialPaths(t *testing.T) {
|
||||||
tests := []struct {
|
tests := map[string]struct {
|
||||||
pattern string
|
pattern string
|
||||||
rootPaths []string
|
rootPaths []string
|
||||||
root bool
|
rootExpected bool
|
||||||
unauthPaths []string
|
unauthenticatedPaths []string
|
||||||
unauth bool
|
unauthenticatedExpected bool
|
||||||
}{
|
}{
|
||||||
{"foo", []string{}, false, []string{"foo"}, true},
|
"empty": {
|
||||||
{"foo", []string{"foo"}, true, []string{"bar"}, false},
|
pattern: "foo",
|
||||||
{"foo/bar", []string{"foo"}, false, []string{"foo/*"}, true},
|
rootPaths: []string{},
|
||||||
{"foo/bar", []string{"foo/*"}, true, []string{"foo"}, false},
|
rootExpected: false,
|
||||||
{"foo/", []string{"foo/*"}, true, []string{"a", "b", "foo/"}, true},
|
unauthenticatedPaths: []string{},
|
||||||
{"foo", []string{"foo*"}, true, []string{"a", "fo*"}, true},
|
unauthenticatedExpected: false,
|
||||||
{"foo/bar", []string{"a", "b", "foo/*"}, true, []string{"foo/baz/*"}, false},
|
},
|
||||||
|
"exact-match-unauthenticated": {
|
||||||
|
pattern: "foo",
|
||||||
|
rootPaths: []string{},
|
||||||
|
rootExpected: false,
|
||||||
|
unauthenticatedPaths: []string{"foo"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"exact-match-root": {
|
||||||
|
pattern: "foo",
|
||||||
|
rootPaths: []string{"foo"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"bar"},
|
||||||
|
unauthenticatedExpected: false,
|
||||||
|
},
|
||||||
|
"asterisk-match-unauthenticated": {
|
||||||
|
pattern: "foo/bar",
|
||||||
|
rootPaths: []string{"foo"},
|
||||||
|
rootExpected: false,
|
||||||
|
unauthenticatedPaths: []string{"foo/*"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"asterisk-match-root": {
|
||||||
|
pattern: "foo/bar",
|
||||||
|
rootPaths: []string{"foo/*"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"foo"},
|
||||||
|
unauthenticatedExpected: false,
|
||||||
|
},
|
||||||
|
"path-ends-with-slash": {
|
||||||
|
pattern: "foo/",
|
||||||
|
rootPaths: []string{"foo/*"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"a", "b", "foo*"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"asterisk-match-no-slash": {
|
||||||
|
pattern: "foo",
|
||||||
|
rootPaths: []string{"foo*"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"a", "fo*"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"multiple-root-paths": {
|
||||||
|
pattern: "foo/bar",
|
||||||
|
rootPaths: []string{"a", "b", "foo/*"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"foo/baz/*"},
|
||||||
|
unauthenticatedExpected: false,
|
||||||
|
},
|
||||||
|
"plus-match-unauthenticated": {
|
||||||
|
pattern: "foo/bar/baz",
|
||||||
|
rootPaths: []string{"foo/bar"},
|
||||||
|
rootExpected: false,
|
||||||
|
unauthenticatedPaths: []string{"foo/+/baz"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"plus-match-root": {
|
||||||
|
pattern: "foo/bar/baz",
|
||||||
|
rootPaths: []string{"foo/+/baz"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"foo/bar"},
|
||||||
|
unauthenticatedExpected: false,
|
||||||
|
},
|
||||||
|
"plus-and-asterisk": {
|
||||||
|
pattern: "foo/bar/baz/something",
|
||||||
|
rootPaths: []string{"foo/+/baz/*"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"foo/+/baz*"},
|
||||||
|
unauthenticatedExpected: true,
|
||||||
|
},
|
||||||
|
"double-plus-good": {
|
||||||
|
pattern: "foo/bar/baz",
|
||||||
|
rootPaths: []string{"foo/+/+"},
|
||||||
|
rootExpected: true,
|
||||||
|
unauthenticatedPaths: []string{"foo/bar"},
|
||||||
|
unauthenticatedExpected: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for i, test := range tests {
|
for name, test := range tests {
|
||||||
doc := NewOASDocument("version")
|
t.Run(name, func(t *testing.T) {
|
||||||
path := Path{
|
doc := NewOASDocument("version")
|
||||||
Pattern: test.pattern,
|
path := Path{
|
||||||
}
|
Pattern: test.pattern,
|
||||||
sp := &logical.Paths{
|
}
|
||||||
Root: test.rootPaths,
|
specialPaths := &logical.Paths{
|
||||||
Unauthenticated: test.unauthPaths,
|
Root: test.rootPaths,
|
||||||
}
|
Unauthenticated: test.unauthenticatedPaths,
|
||||||
err := documentPath(&path, sp, "kv", logical.TypeLogical, doc)
|
}
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
if err := documentPath(&path, specialPaths, "kv", logical.TypeLogical, doc); err != nil {
|
||||||
}
|
t.Fatal(err)
|
||||||
result := test.root
|
}
|
||||||
if doc.Paths["/"+test.pattern].Sudo != result {
|
|
||||||
t.Fatalf("Test (root) %d: Expected %v got %v", i, test.root, result)
|
actual := doc.Paths["/"+test.pattern].Sudo
|
||||||
}
|
if actual != test.rootExpected {
|
||||||
result = test.unauth
|
t.Fatalf("Test (root): expected: %v; got: %v", test.rootExpected, actual)
|
||||||
if doc.Paths["/"+test.pattern].Unauthenticated != result {
|
}
|
||||||
t.Fatalf("Test (unauth) %d: Expected %v got %v", i, test.unauth, result)
|
|
||||||
}
|
actual = doc.Paths["/"+test.pattern].Unauthenticated
|
||||||
|
if actual != test.unauthenticatedExpected {
|
||||||
|
t.Fatalf("Test (unauth): expected: %v; got: %v", test.unauthenticatedExpected, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue