go.etcd.io/etcd@v3.3.27+incompatible/etcdctl/ctlv3/command/role_command.go (about) 1 // Copyright 2016 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package command 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/coreos/etcd/clientv3" 22 "github.com/spf13/cobra" 23 ) 24 25 var ( 26 rolePermPrefix bool 27 rolePermFromKey bool 28 ) 29 30 // NewRoleCommand returns the cobra command for "role". 31 func NewRoleCommand() *cobra.Command { 32 ac := &cobra.Command{ 33 Use: "role <subcommand>", 34 Short: "Role related commands", 35 } 36 37 ac.AddCommand(newRoleAddCommand()) 38 ac.AddCommand(newRoleDeleteCommand()) 39 ac.AddCommand(newRoleGetCommand()) 40 ac.AddCommand(newRoleListCommand()) 41 ac.AddCommand(newRoleGrantPermissionCommand()) 42 ac.AddCommand(newRoleRevokePermissionCommand()) 43 44 return ac 45 } 46 47 func newRoleAddCommand() *cobra.Command { 48 return &cobra.Command{ 49 Use: "add <role name>", 50 Short: "Adds a new role", 51 Run: roleAddCommandFunc, 52 } 53 } 54 55 func newRoleDeleteCommand() *cobra.Command { 56 return &cobra.Command{ 57 Use: "delete <role name>", 58 Short: "Deletes a role", 59 Run: roleDeleteCommandFunc, 60 } 61 } 62 63 func newRoleGetCommand() *cobra.Command { 64 return &cobra.Command{ 65 Use: "get <role name>", 66 Short: "Gets detailed information of a role", 67 Run: roleGetCommandFunc, 68 } 69 } 70 71 func newRoleListCommand() *cobra.Command { 72 return &cobra.Command{ 73 Use: "list", 74 Short: "Lists all roles", 75 Run: roleListCommandFunc, 76 } 77 } 78 79 func newRoleGrantPermissionCommand() *cobra.Command { 80 cmd := &cobra.Command{ 81 Use: "grant-permission [options] <role name> <permission type> <key> [endkey]", 82 Short: "Grants a key to a role", 83 Run: roleGrantPermissionCommandFunc, 84 } 85 86 cmd.Flags().BoolVar(&rolePermPrefix, "prefix", false, "grant a prefix permission") 87 cmd.Flags().BoolVar(&rolePermFromKey, "from-key", false, "grant a permission of keys that are greater than or equal to the given key using byte compare") 88 89 return cmd 90 } 91 92 func newRoleRevokePermissionCommand() *cobra.Command { 93 cmd := &cobra.Command{ 94 Use: "revoke-permission <role name> <key> [endkey]", 95 Short: "Revokes a key from a role", 96 Run: roleRevokePermissionCommandFunc, 97 } 98 99 cmd.Flags().BoolVar(&rolePermPrefix, "prefix", false, "revoke a prefix permission") 100 cmd.Flags().BoolVar(&rolePermFromKey, "from-key", false, "revoke a permission of keys that are greater than or equal to the given key using byte compare") 101 102 return cmd 103 } 104 105 // roleAddCommandFunc executes the "role add" command. 106 func roleAddCommandFunc(cmd *cobra.Command, args []string) { 107 if len(args) != 1 { 108 ExitWithError(ExitBadArgs, fmt.Errorf("role add command requires role name as its argument.")) 109 } 110 111 resp, err := mustClientFromCmd(cmd).Auth.RoleAdd(context.TODO(), args[0]) 112 if err != nil { 113 ExitWithError(ExitError, err) 114 } 115 116 display.RoleAdd(args[0], *resp) 117 } 118 119 // roleDeleteCommandFunc executes the "role delete" command. 120 func roleDeleteCommandFunc(cmd *cobra.Command, args []string) { 121 if len(args) != 1 { 122 ExitWithError(ExitBadArgs, fmt.Errorf("role delete command requires role name as its argument.")) 123 } 124 125 resp, err := mustClientFromCmd(cmd).Auth.RoleDelete(context.TODO(), args[0]) 126 if err != nil { 127 ExitWithError(ExitError, err) 128 } 129 130 display.RoleDelete(args[0], *resp) 131 } 132 133 // roleGetCommandFunc executes the "role get" command. 134 func roleGetCommandFunc(cmd *cobra.Command, args []string) { 135 if len(args) != 1 { 136 ExitWithError(ExitBadArgs, fmt.Errorf("role get command requires role name as its argument.")) 137 } 138 139 name := args[0] 140 resp, err := mustClientFromCmd(cmd).Auth.RoleGet(context.TODO(), name) 141 if err != nil { 142 ExitWithError(ExitError, err) 143 } 144 145 display.RoleGet(name, *resp) 146 } 147 148 // roleListCommandFunc executes the "role list" command. 149 func roleListCommandFunc(cmd *cobra.Command, args []string) { 150 if len(args) != 0 { 151 ExitWithError(ExitBadArgs, fmt.Errorf("role list command requires no arguments.")) 152 } 153 154 resp, err := mustClientFromCmd(cmd).Auth.RoleList(context.TODO()) 155 if err != nil { 156 ExitWithError(ExitError, err) 157 } 158 159 display.RoleList(*resp) 160 } 161 162 // roleGrantPermissionCommandFunc executes the "role grant-permission" command. 163 func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) { 164 if len(args) < 3 { 165 ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key [endkey] as its argument.")) 166 } 167 168 perm, err := clientv3.StrToPermissionType(args[1]) 169 if err != nil { 170 ExitWithError(ExitBadArgs, err) 171 } 172 173 key, rangeEnd := permRange(args[2:]) 174 resp, err := mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], key, rangeEnd, perm) 175 if err != nil { 176 ExitWithError(ExitError, err) 177 } 178 179 display.RoleGrantPermission(args[0], *resp) 180 } 181 182 // roleRevokePermissionCommandFunc executes the "role revoke-permission" command. 183 func roleRevokePermissionCommandFunc(cmd *cobra.Command, args []string) { 184 if len(args) < 2 { 185 ExitWithError(ExitBadArgs, fmt.Errorf("role revoke-permission command requires role name and key [endkey] as its argument.")) 186 } 187 188 key, rangeEnd := permRange(args[1:]) 189 resp, err := mustClientFromCmd(cmd).Auth.RoleRevokePermission(context.TODO(), args[0], key, rangeEnd) 190 if err != nil { 191 ExitWithError(ExitError, err) 192 } 193 display.RoleRevokePermission(args[0], args[1], rangeEnd, *resp) 194 } 195 196 func permRange(args []string) (string, string) { 197 key := args[0] 198 var rangeEnd string 199 if len(key) == 0 { 200 if rolePermPrefix && rolePermFromKey { 201 ExitWithError(ExitBadArgs, fmt.Errorf("--from-key and --prefix flags are mutually exclusive")) 202 } 203 204 // Range permission is expressed as adt.BytesAffineInterval, 205 // so the empty prefix which should be matched with every key must be like this ["\x00", <end>). 206 key = "\x00" 207 if rolePermPrefix || rolePermFromKey { 208 // For the both cases of prefix and from-key, a permission with an empty key 209 // should allow access to the entire key space. 210 // 0x00 will be treated as open ended in server side. 211 rangeEnd = "\x00" 212 } 213 } else { 214 var err error 215 rangeEnd, err = rangeEndFromPermFlags(args[0:]) 216 if err != nil { 217 ExitWithError(ExitBadArgs, err) 218 } 219 } 220 return key, rangeEnd 221 } 222 223 func rangeEndFromPermFlags(args []string) (string, error) { 224 if len(args) == 1 { 225 if rolePermPrefix { 226 if rolePermFromKey { 227 return "", fmt.Errorf("--from-key and --prefix flags are mutually exclusive") 228 } 229 return clientv3.GetPrefixRangeEnd(args[0]), nil 230 } 231 if rolePermFromKey { 232 return "\x00", nil 233 } 234 // single key case 235 return "", nil 236 } 237 if rolePermPrefix { 238 return "", fmt.Errorf("unexpected endkey argument with --prefix flag") 239 } 240 if rolePermFromKey { 241 return "", fmt.Errorf("unexpected endkey argument with --from-key flag") 242 } 243 return args[1], nil 244 }