diff --git a/auth/range_perm_cache.go b/auth/range_perm_cache.go index 8f4d9f5db68..a6989aaa2ee 100644 --- a/auth/range_perm_cache.go +++ b/auth/range_perm_cache.go @@ -38,11 +38,18 @@ func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermission for _, perm := range role.KeyPermission { var ivl adt.Interval + var rangeEnd string + + if len(perm.RangeEnd) == 1 && perm.RangeEnd[0] == 0 { + rangeEnd = "" + } else { + rangeEnd = string(perm.RangeEnd) + } if len(perm.RangeEnd) != 0 { - ivl = adt.NewStringInterval(string(perm.Key), string(perm.RangeEnd)) + ivl = adt.NewStringAffineInterval(string(perm.Key), string(rangeEnd)) } else { - ivl = adt.NewStringPoint(string(perm.Key)) + ivl = adt.NewStringAffinePoint(string(perm.Key)) } switch perm.PermType { @@ -66,7 +73,11 @@ func getMergedPerms(tx backend.BatchTx, userName string) *unifiedRangePermission } func checkKeyInterval(cachedPerms *unifiedRangePermissions, key, rangeEnd string, permtyp authpb.Permission_Type) bool { - ivl := adt.NewStringInterval(key, rangeEnd) + if len(rangeEnd) == 1 && rangeEnd[0] == '\x00' { + rangeEnd = "" + } + + ivl := adt.NewStringAffineInterval(key, rangeEnd) switch permtyp { case authpb.READ: return cachedPerms.readPerms.Contains(ivl) @@ -79,7 +90,7 @@ func checkKeyInterval(cachedPerms *unifiedRangePermissions, key, rangeEnd string } func checkKeyPoint(cachedPerms *unifiedRangePermissions, key string, permtyp authpb.Permission_Type) bool { - pt := adt.NewStringPoint(key) + pt := adt.NewStringAffinePoint(key) switch permtyp { case authpb.READ: return cachedPerms.readPerms.Intersects(pt) diff --git a/auth/range_perm_cache_test.go b/auth/range_perm_cache_test.go index 0665e5d7971..8629e73a48a 100644 --- a/auth/range_perm_cache_test.go +++ b/auth/range_perm_cache_test.go @@ -29,17 +29,17 @@ func TestRangePermission(t *testing.T) { want bool }{ { - []adt.Interval{adt.NewStringInterval("a", "c"), adt.NewStringInterval("x", "z")}, + []adt.Interval{adt.NewStringAffineInterval("a", "c"), adt.NewStringAffineInterval("x", "z")}, "a", "z", false, }, { - []adt.Interval{adt.NewStringInterval("a", "f"), adt.NewStringInterval("c", "d"), adt.NewStringInterval("f", "z")}, + []adt.Interval{adt.NewStringAffineInterval("a", "f"), adt.NewStringAffineInterval("c", "d"), adt.NewStringAffineInterval("f", "z")}, "a", "z", true, }, { - []adt.Interval{adt.NewStringInterval("a", "d"), adt.NewStringInterval("a", "b"), adt.NewStringInterval("c", "f")}, + []adt.Interval{adt.NewStringAffineInterval("a", "d"), adt.NewStringAffineInterval("a", "b"), adt.NewStringAffineInterval("c", "f")}, "a", "f", true, }, diff --git a/etcdctl/ctlv3/command/printer_simple.go b/etcdctl/ctlv3/command/printer_simple.go index 2d0bf1a3e69..96e1032e6e1 100644 --- a/etcdctl/ctlv3/command/printer_simple.go +++ b/etcdctl/ctlv3/command/printer_simple.go @@ -141,7 +141,11 @@ func (s *simplePrinter) RoleGet(role string, r v3.AuthRoleGetResponse) { printRange := func(perm *v3.Permission) { sKey := string(perm.Key) sRangeEnd := string(perm.RangeEnd) - fmt.Printf("\t[%s, %s)", sKey, sRangeEnd) + if strings.Compare(sRangeEnd, "\x00") != 0 { + fmt.Printf("\t[%s, %s)", sKey, sRangeEnd) + } else { + fmt.Printf("\t[%s, ", sKey) + } if strings.Compare(v3.GetPrefixRangeEnd(sKey), sRangeEnd) == 0 { fmt.Printf(" (prefix %s)", sKey) } @@ -188,7 +192,11 @@ func (s *simplePrinter) RoleRevokePermission(role string, key string, end string fmt.Printf("Permission of key %s is revoked from role %s\n", key, role) return } - fmt.Printf("Permission of range [%s, %s) is revoked from role %s\n", key, end, role) + if strings.Compare(end, "\x00") != 0 { + fmt.Printf("Permission of range [%s, %s) is revoked from role %s\n", key, end, role) + } else { + fmt.Printf("Permission of range [%s, is revoked from role %s\n", key, role) + } } func (s *simplePrinter) UserAdd(name string, r v3.AuthUserAddResponse) { diff --git a/etcdctl/ctlv3/command/role_command.go b/etcdctl/ctlv3/command/role_command.go index 28d12f24596..f75a8efceb4 100644 --- a/etcdctl/ctlv3/command/role_command.go +++ b/etcdctl/ctlv3/command/role_command.go @@ -24,6 +24,7 @@ import ( var ( grantPermissionPrefix bool + permFromKey bool ) // NewRoleCommand returns the cobra command for "role". @@ -83,16 +84,21 @@ func newRoleGrantPermissionCommand() *cobra.Command { } cmd.Flags().BoolVar(&grantPermissionPrefix, "prefix", false, "grant a prefix permission") + cmd.Flags().BoolVar(&permFromKey, "from-key", false, "grant a permission of keys that are greater than or equal to the given key using byte compare") return cmd } func newRoleRevokePermissionCommand() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "revoke-permission [endkey]", Short: "Revokes a key from a role", Run: roleRevokePermissionCommandFunc, } + + cmd.Flags().BoolVar(&permFromKey, "from-key", false, "grant a permission of keys that are greater than or equal to the given key using byte compare") + + return cmd } // roleAddCommandFunc executes the "role add" command. @@ -168,9 +174,20 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) { if grantPermissionPrefix { ExitWithError(ExitBadArgs, fmt.Errorf("don't pass both of --prefix option and range end to grant permission command")) } + + if permFromKey { + ExitWithError(ExitBadArgs, fmt.Errorf("don't pass both of --from-key option and range end to grant permission command")) + } + rangeEnd = args[3] } else if grantPermissionPrefix { + if permFromKey { + ExitWithError(ExitBadArgs, fmt.Errorf("don't pass both of --from-key option and --prefix option to grant permission command")) + } + rangeEnd = clientv3.GetPrefixRangeEnd(args[2]) + } else if permFromKey { + rangeEnd = "\x00" } resp, err := mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm) @@ -190,6 +207,8 @@ func roleRevokePermissionCommandFunc(cmd *cobra.Command, args []string) { rangeEnd := "" if 3 <= len(args) { rangeEnd = args[2] + } else if permFromKey { + rangeEnd = "\x00" } resp, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], args[1], rangeEnd)