Commit db635bf8 authored by Danielle Tomlinson's avatar Danielle Tomlinson
Browse files

fixup: Correctly sort based on distance, use iradix for ordering

parent 36d1045e
Showing with 58 additions and 15 deletions
+58 -15
......@@ -48,7 +48,8 @@ type ACL struct {
namespaces *iradix.Tree
// wildcardNamespaces maps a glob pattern of a namespace to a capabilitySet
wildcardNamespaces map[string]capabilitySet
// We use an iradix for the purposes of ordered iteration.
wildcardNamespaces *iradix.Tree
agent string
node string
......@@ -81,7 +82,7 @@ func NewACL(management bool, policies []*Policy) (*ACL, error) {
// Create the ACL object
acl := &ACL{}
nsTxn := iradix.New().Txn()
wns := make(map[string]capabilitySet)
wnsTxn := iradix.New().Txn()
for _, policy := range policies {
NAMESPACES:
......@@ -93,12 +94,12 @@ func NewACL(management bool, policies []*Policy) (*ACL, error) {
var capabilities capabilitySet
if globDefinition {
raw, ok := wns[ns.Name]
raw, ok := wnsTxn.Get([]byte(ns.Name))
if ok {
capabilities = raw
capabilities = raw.(capabilitySet)
} else {
capabilities = make(capabilitySet)
wns[ns.Name] = capabilities
wnsTxn.Insert([]byte(ns.Name), capabilities)
}
} else {
raw, ok := nsTxn.Get([]byte(ns.Name))
......@@ -144,7 +145,7 @@ func NewACL(management bool, policies []*Policy) (*ACL, error) {
// Finalize the namespaces
acl.namespaces = nsTxn.Commit()
acl.wildcardNamespaces = wns
acl.wildcardNamespaces = wnsTxn.Commit()
return acl, nil
}
......@@ -211,7 +212,7 @@ func (a *ACL) matchingCapabilitySet(ns string) (capabilitySet, bool) {
type matchingGlob struct {
ns string
nsLen int
difference int
capabilitySet capabilitySet
}
......@@ -229,13 +230,11 @@ func (a *ACL) findClosestMatchingGlob(ns string) (capabilitySet, bool) {
return matchingGlobs[0].capabilitySet, true
}
nsLen := len(ns)
// Stable sort the matched globs, based on the character difference between
// the glob definition and the requested namespace. This allows us to be
// more consistent about results based on the policy definition.
sort.SliceStable(matchingGlobs, func(i, j int) bool {
return (matchingGlobs[i].nsLen - nsLen) >= (matchingGlobs[j].nsLen - nsLen)
return matchingGlobs[i].difference <= matchingGlobs[j].difference
})
return matchingGlobs[0].capabilitySet, true
......@@ -244,17 +243,26 @@ func (a *ACL) findClosestMatchingGlob(ns string) (capabilitySet, bool) {
func (a *ACL) findAllMatchingWildcards(ns string) []matchingGlob {
var matches []matchingGlob
for k, v := range a.wildcardNamespaces {
isMatch := glob.Glob(string(k), ns)
nsLen := len(ns)
a.wildcardNamespaces.Root().Walk(func(bk []byte, iv interface{}) bool {
k := string(bk)
v := iv.(capabilitySet)
isMatch := glob.Glob(k, ns)
if isMatch {
globLen := len(strings.Replace(k, glob.GLOB, "", -1))
pair := matchingGlob{
ns: k,
nsLen: len(k),
difference: nsLen - globLen,
capabilitySet: v,
}
matches = append(matches, pair)
}
}
// We always want to walk the entire tree, never terminate early.
return false
})
return matches
}
......
......@@ -309,7 +309,7 @@ func TestWildcardNamespaceMatching(t *testing.T) {
}
}
func TestACL_matchingCapabilitySet(t *testing.T) {
func TestACL_matchingCapabilitySet_returnsAllMatches(t *testing.T) {
tests := []struct {
Policy string
NS string
......@@ -353,5 +353,40 @@ func TestACL_matchingCapabilitySet(t *testing.T) {
assert.Equal(tc.MatchingGlobs, namespaces)
})
}
}
func TestACL_matchingCapabilitySet_difference(t *testing.T) {
tests := []struct {
Policy string
NS string
Difference int
}{
{
Policy: `namespace "production-*" { policy = "write" }`,
NS: "production-api",
Difference: 3,
},
{
Policy: `namespace "production-*" { policy = "write" }`,
NS: "production-admin-api",
Difference: 9,
},
}
for _, tc := range tests {
t.Run(tc.Policy, func(t *testing.T) {
assert := assert.New(t)
policy, err := Parse(tc.Policy)
assert.NoError(err)
assert.NotNil(policy.Namespaces)
acl, err := NewACL(false, []*Policy{policy})
assert.Nil(err)
matches := acl.findAllMatchingWildcards(tc.NS)
assert.Equal(tc.Difference, matches[0].difference)
})
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment