Browse Source

Merge pull request #6414 from mitake/prefix-perm

etcdctl: an option for granting permission with key prefix
Xiang Li 9 years ago
parent
commit
672472f85e
3 changed files with 53 additions and 4 deletions
  1. 35 3
      e2e/ctl_v3_auth_test.go
  2. 4 0
      e2e/ctl_v3_role_test.go
  3. 14 1
      etcdctl/ctlv3/command/role_command.go

+ 35 - 3
e2e/ctl_v3_auth_test.go

@@ -17,6 +17,8 @@ package e2e
 import (
 	"fmt"
 	"testing"
+
+	"github.com/coreos/etcd/clientv3"
 )
 
 func TestCtlV3AuthEnable(t *testing.T)              { testCtl(t, authEnableTest) }
@@ -26,6 +28,7 @@ func TestCtlV3AuthRoleUpdate(t *testing.T)          { testCtl(t, authRoleUpdateT
 func TestCtlV3AuthUserDeleteDuringOps(t *testing.T) { testCtl(t, authUserDeleteDuringOpsTest) }
 func TestCtlV3AuthRoleRevokeDuringOps(t *testing.T) { testCtl(t, authRoleRevokeDuringOpsTest) }
 func TestCtlV3AuthTxn(t *testing.T)                 { testCtl(t, authTestTxn) }
+func TestCtlV3AuthPerfixPerm(t *testing.T)          { testCtl(t, authTestPrefixPerm) }
 
 func authEnableTest(cx ctlCtx) {
 	if err := authEnable(cx); err != nil {
@@ -172,7 +175,7 @@ func authRoleUpdateTest(cx ctlCtx) {
 
 	// grant a new key
 	cx.user, cx.pass = "root", "root"
-	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", ""}); err != nil {
+	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil {
 		cx.t.Fatal(err)
 	}
 
@@ -268,7 +271,7 @@ func authRoleRevokeDuringOpsTest(cx ctlCtx) {
 		cx.t.Fatal(err)
 	}
 	// grant a new key to the new role
-	if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", ""}); err != nil {
+	if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil {
 		cx.t.Fatal(err)
 	}
 	// grant the new role to the user
@@ -370,7 +373,7 @@ func authTestTxn(cx ctlCtx) {
 	// grant keys to test-user
 	cx.user, cx.pass = "root", "root"
 	for _, key := range grantedKeys {
-		if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, ""}); err != nil {
+		if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, key, "", false}); err != nil {
 			cx.t.Fatal(err)
 		}
 	}
@@ -422,3 +425,32 @@ func authTestTxn(cx ctlCtx) {
 		cx.t.Fatal(err)
 	}
 }
+
+func authTestPrefixPerm(cx ctlCtx) {
+	if err := authEnable(cx); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	cx.user, cx.pass = "root", "root"
+	authSetupTestUser(cx)
+
+	prefix := "/prefix/" // directory like prefix
+	// grant keys to test-user
+	cx.user, cx.pass = "root", "root"
+	if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, prefix, "", true}); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	// try a prefix granted permission
+	cx.user, cx.pass = "test-user", "pass"
+	for i := 0; i < 10; i++ {
+		key := fmt.Sprintf("%s%d", prefix, i)
+		if err := ctlV3Put(cx, key, "val", ""); err != nil {
+			cx.t.Fatal(err)
+		}
+	}
+
+	if err := ctlV3PutFailPerm(cx, clientv3.GetPrefixRangeEnd(prefix), "baz"); err != nil {
+		cx.t.Fatal(err)
+	}
+}

+ 4 - 0
e2e/ctl_v3_role_test.go

@@ -101,6 +101,9 @@ func ctlV3Role(cx ctlCtx, args []string, expStr string) error {
 
 func ctlV3RoleGrantPermission(cx ctlCtx, rolename string, perm grantingPerm) error {
 	cmdArgs := append(cx.PrefixArgs(), "role", "grant-permission")
+	if perm.prefix {
+		cmdArgs = append(cmdArgs, "--prefix")
+	}
 	cmdArgs = append(cmdArgs, rolename)
 	cmdArgs = append(cmdArgs, grantingPermToArgs(perm)...)
 
@@ -137,6 +140,7 @@ type grantingPerm struct {
 	write    bool
 	key      string
 	rangeEnd string
+	prefix   bool
 }
 
 func grantingPermToArgs(perm grantingPerm) []string {

+ 14 - 1
etcdctl/ctlv3/command/role_command.go

@@ -22,6 +22,10 @@ import (
 	"golang.org/x/net/context"
 )
 
+var (
+	grantPermissionPrefix bool
+)
+
 // NewRoleCommand returns the cobra command for "role".
 func NewRoleCommand() *cobra.Command {
 	ac := &cobra.Command{
@@ -72,11 +76,15 @@ func newRoleListCommand() *cobra.Command {
 }
 
 func newRoleGrantPermissionCommand() *cobra.Command {
-	return &cobra.Command{
+	cmd := &cobra.Command{
 		Use:   "grant-permission <role name> <permission type> <key> [endkey]",
 		Short: "Grants a key to a role",
 		Run:   roleGrantPermissionCommandFunc,
 	}
+
+	cmd.Flags().BoolVar(&grantPermissionPrefix, "prefix", false, "grant a prefix permission")
+
+	return cmd
 }
 
 func newRoleRevokePermissionCommand() *cobra.Command {
@@ -183,7 +191,12 @@ func roleGrantPermissionCommandFunc(cmd *cobra.Command, args []string) {
 
 	rangeEnd := ""
 	if 4 <= len(args) {
+		if grantPermissionPrefix {
+			ExitWithError(ExitBadArgs, fmt.Errorf("don't pass both of --prefix option and range end to grant permission command"))
+		}
 		rangeEnd = args[3]
+	} else if grantPermissionPrefix {
+		rangeEnd = clientv3.GetPrefixRangeEnd(args[2])
 	}
 
 	_, err = mustClientFromCmd(cmd).Auth.RoleGrantPermission(context.TODO(), args[0], args[2], rangeEnd, perm)