Pārlūkot izejas kodu

Merge pull request #5622 from heyitsanthony/e2e-auth-keys

e2e: auth key put test
Anthony Romano 9 gadi atpakaļ
vecāks
revīzija
e854fa1856
3 mainītis faili ar 115 papildinājumiem un 8 dzēšanām
  1. 99 8
      e2e/ctl_v3_auth_test.go
  2. 7 0
      e2e/ctl_v3_test.go
  3. 9 0
      etcdserver/v3_server.go

+ 99 - 8
e2e/ctl_v3_auth_test.go

@@ -14,24 +14,33 @@
 
 package e2e
 
-import "testing"
+import (
+	"fmt"
+	"testing"
+)
 
-func TestCtlV3AuthEnable(t *testing.T)  { testCtl(t, authEnableTest) }
-func TestCtlV3AuthDisable(t *testing.T) { testCtl(t, authDisableTest) }
+func TestCtlV3AuthEnable(t *testing.T)   { testCtl(t, authEnableTest) }
+func TestCtlV3AuthDisable(t *testing.T)  { testCtl(t, authDisableTest) }
+func TestCtlV3AuthWriteKey(t *testing.T) { testCtl(t, authCredWriteKeyTest) }
 
 func authEnableTest(cx ctlCtx) {
+	if err := authEnable(cx); err != nil {
+		cx.t.Fatal(err)
+	}
+}
+
+func authEnable(cx ctlCtx) error {
 	// create root user with root role
 	if err := ctlV3User(cx, []string{"add", "root", "--interactive=false"}, "User root created", []string{"root"}); err != nil {
-		cx.t.Fatalf("failed to create root user %v", err)
+		return fmt.Errorf("failed to create root user %v", err)
 	}
-
 	if err := ctlV3User(cx, []string{"grant-role", "root", "root"}, "Role root is granted to user root", nil); err != nil {
-		cx.t.Fatalf("failed to grant root user root role %v", err)
+		return fmt.Errorf("failed to grant root user root role %v", err)
 	}
-
 	if err := ctlV3AuthEnable(cx); err != nil {
-		cx.t.Fatalf("authEnableTest ctlV3AuthEnable error (%v)", err)
+		return fmt.Errorf("authEnableTest ctlV3AuthEnable error (%v)", err)
 	}
+	return nil
 }
 
 func ctlV3AuthEnable(cx ctlCtx) error {
@@ -49,3 +58,85 @@ func ctlV3AuthDisable(cx ctlCtx) error {
 	cmdArgs := append(cx.PrefixArgs(), "auth", "disable")
 	return spawnWithExpect(cmdArgs, "Authentication Disabled")
 }
+
+func authCredWriteKeyTest(cx ctlCtx) {
+	// baseline key to check for failed puts
+	if err := ctlV3Put(cx, "foo", "a", ""); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	if err := authEnable(cx); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	cx.user, cx.pass = "root", "root"
+	authSetupTestUser(cx)
+
+	// confirm root role doesn't grant access to all keys
+	if err := ctlV3PutFailPerm(cx, "foo", "bar"); err != nil {
+		cx.t.Fatal(err)
+	}
+	if err := ctlV3GetFailPerm(cx, "foo"); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	// try invalid user
+	cx.user, cx.pass = "a", "b"
+	if err := ctlV3PutFailAuth(cx, "foo", "bar"); err != nil {
+		cx.t.Fatal(err)
+	}
+	// confirm put failed
+	cx.user, cx.pass = "test-user", "pass"
+	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "a"}}...); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	// try good user
+	cx.user, cx.pass = "test-user", "pass"
+	if err := ctlV3Put(cx, "foo", "bar", ""); err != nil {
+		cx.t.Fatal(err)
+	}
+	// confirm put succeeded
+	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
+		cx.t.Fatal(err)
+	}
+
+	// try bad password
+	cx.user, cx.pass = "test-user", "badpass"
+	if err := ctlV3PutFailAuth(cx, "foo", "baz"); err != nil {
+		cx.t.Fatal(err)
+	}
+	// confirm put failed
+	cx.user, cx.pass = "test-user", "pass"
+	if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil {
+		cx.t.Fatal(err)
+	}
+}
+
+func ctlV3PutFailAuth(cx ctlCtx, key, val string) error {
+	return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "authentication failed")
+}
+
+func ctlV3PutFailPerm(cx ctlCtx, key, val string) error {
+	return spawnWithExpect(append(cx.PrefixArgs(), "put", key, val), "permission denied")
+}
+
+func ctlV3GetFailPerm(cx ctlCtx, key string) error {
+	return spawnWithExpect(append(cx.PrefixArgs(), "get", key), "permission denied")
+}
+
+func authSetupTestUser(cx ctlCtx) {
+	if err := ctlV3User(cx, []string{"add", "test-user", "--interactive=false"}, "User test-user created", []string{"pass"}); err != nil {
+		cx.t.Fatal(err)
+	}
+	if err := spawnWithExpect(append(cx.PrefixArgs(), "role", "add", "test-role"), "Role test-role created"); err != nil {
+		cx.t.Fatal(err)
+	}
+	if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role"}, "Role test-role is granted to user test-user", nil); err != nil {
+		cx.t.Fatal(err)
+	}
+	cmd := append(cx.PrefixArgs(), "role", "grant-permission", "test-role", "readwrite", "foo")
+	if err := spawnWithExpect(cmd, "Role test-role updated"); err != nil {
+		cx.t.Fatal(err)
+	}
+}

+ 7 - 0
e2e/ctl_v3_test.go

@@ -48,6 +48,9 @@ type ctlCtx struct {
 
 	quorum      bool // if true, set up 3-node cluster and linearizable read
 	interactive bool
+
+	user string
+	pass string
 }
 
 type ctlOption func(*ctlCtx)
@@ -147,6 +150,10 @@ func (cx *ctlCtx) PrefixArgs() []string {
 		}
 	}
 
+	if cx.user != "" {
+		cmdArgs = append(cmdArgs, "--user="+cx.user+":"+cx.pass)
+	}
+
 	return cmdArgs
 }
 

+ 9 - 0
etcdserver/v3_server.go

@@ -17,6 +17,7 @@ package etcdserver
 import (
 	"time"
 
+	"github.com/coreos/etcd/auth"
 	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
 	"github.com/coreos/etcd/lease"
 	"github.com/coreos/etcd/lease/leasehttp"
@@ -74,6 +75,14 @@ type Authenticator interface {
 
 func (s *EtcdServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
 	if r.Serializable {
+		user, err := s.usernameFromCtx(ctx)
+		if err != nil {
+			return nil, err
+		}
+		hdr := &pb.RequestHeader{Username: user}
+		if !s.AuthStore().IsRangePermitted(hdr, string(r.Key), string(r.RangeEnd)) {
+			return nil, auth.ErrPermissionDenied
+		}
 		return s.applyV3.Range(noTxn, r)
 	}