diff --git a/auth/range_perm_cache.go b/auth/range_perm_cache.go index 613deecbf..b205544b7 100644 --- a/auth/range_perm_cache.go +++ b/auth/range_perm_cache.go @@ -22,9 +22,20 @@ import ( "github.com/coreos/etcd/mvcc/backend" ) +// isSubset returns true if a is a subset of b func isSubset(a, b *rangePerm) bool { - // return true if a is a subset of b - return 0 <= bytes.Compare(a.begin, b.begin) && bytes.Compare(a.end, b.end) <= 0 + switch { + case len(a.end) == 0 && len(b.end) == 0: + // a, b are both keys + return bytes.Compare(a.begin, b.begin) == 0 + case len(b.end) == 0: + // b is a key, a is a range + return false + case len(a.end) == 0: + return 0 <= bytes.Compare(a.begin, b.begin) && bytes.Compare(a.begin, b.end) <= 0 + default: + return 0 <= bytes.Compare(a.begin, b.begin) && bytes.Compare(a.end, b.end) <= 0 + } } // removeSubsetRangePerms removes any rangePerms that are subsets of other rangePerms. @@ -126,15 +137,10 @@ func checkKeyPerm(cachedPerms *unifiedRangePermissions, key, rangeEnd []byte, pe plog.Panicf("unknown auth type: %v", permtyp) } - for _, perm := range tocheck { - // check permission of a single key - if len(rangeEnd) == 0 { - if bytes.Compare(perm.begin, key) <= 0 && bytes.Compare(rangeEnd, perm.end) <= 0 { - return true - } - } + requiredPerm := &rangePerm{begin: key, end: rangeEnd} - if bytes.Compare(perm.begin, key) <= 0 && bytes.Compare(perm.end, key) >= 0 { + for _, perm := range tocheck { + if isSubset(requiredPerm, perm) { return true } } diff --git a/auth/range_perm_cache_test.go b/auth/range_perm_cache_test.go index 2df3e6848..7f7dff6e3 100644 --- a/auth/range_perm_cache_test.go +++ b/auth/range_perm_cache_test.go @@ -37,7 +37,7 @@ func isPermsEqual(a, b []*rangePerm) bool { return true } -func TestUnifyParams(t *testing.T) { +func TestGetMergedPerms(t *testing.T) { tests := []struct { params []*rangePerm want []*rangePerm @@ -86,6 +86,28 @@ func TestUnifyParams(t *testing.T) { []*rangePerm{{[]byte("a"), []byte("b")}, {[]byte("b"), []byte("c")}, {[]byte("c"), []byte("d")}, {[]byte("d"), []byte("f")}, {[]byte("1"), []byte("9")}}, []*rangePerm{{[]byte("1"), []byte("9")}, {[]byte("a"), []byte("f")}}, }, + // overlapping + { + []*rangePerm{{[]byte("a"), []byte("f")}, {[]byte("b"), []byte("g")}}, + []*rangePerm{{[]byte("a"), []byte("g")}}, + }, + // keys + { + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("")}}, + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("")}}, + }, + { + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("a"), []byte("c")}}, + []*rangePerm{{[]byte("a"), []byte("c")}}, + }, + { + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("a"), []byte("c")}, {[]byte("b"), []byte("")}}, + []*rangePerm{{[]byte("a"), []byte("c")}}, + }, + { + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("c")}, {[]byte("b"), []byte("")}, {[]byte("c"), []byte("")}, {[]byte("d"), []byte("")}}, + []*rangePerm{{[]byte("a"), []byte("")}, {[]byte("b"), []byte("c")}, {[]byte("d"), []byte("")}}, + }, } for i, tt := range tests {