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  }