diff --git a/tests/common/auth_test.go b/tests/common/auth_test.go index d1e748747a0a..432f5e419298 100644 --- a/tests/common/auth_test.go +++ b/tests/common/auth_test.go @@ -16,15 +16,24 @@ package common import ( "context" + "fmt" + "path/filepath" + "strings" "testing" "time" - "github.com/stretchr/testify/require" - + "go.etcd.io/etcd/api/v3/v3rpc/rpctypes" + clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/tests/v3/framework/config" + "go.etcd.io/etcd/tests/v3/framework/interfaces" "go.etcd.io/etcd/tests/v3/framework/testutils" + + "github.com/stretchr/testify/require" ) +var defaultAuthToken = fmt.Sprintf("jwt,pub-key=%s,priv-key=%s,sign-method=RS256,ttl=1s", + mustAbsPath("../fixtures/server.crt"), mustAbsPath("../fixtures/server.key.insecure")) + func TestAuthEnable(t *testing.T) { testRunner.BeforeTest(t) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -131,3 +140,287 @@ func TestAuthStatus(t *testing.T) { require.Truef(t, resp.Enabled, "want enabled but got not enabled") }) } + +func TestAuthRoleUpdate(t *testing.T) { + testRunner.BeforeTest(t) + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(config.ClusterConfig{ClusterSize: 1})) + defer clus.Close() + cc := testutils.MustClient(clus.Client()) + testutils.ExecuteUntil(ctx, t, func() { + require.NoError(t, cc.Put(ctx, "foo", "bar", config.PutOptions{})) + require.NoErrorf(t, setupAuth(cc, []authRole{testRole}, []authUser{rootUser, testUser}), "failed to enable auth") + + rootAuthClient := testutils.MustClient(clus.Client(WithAuth(rootUserName, rootPassword))) + testUserAuthClient := testutils.MustClient(clus.Client(WithAuth(testUserName, testPassword))) + + putFailPerm(ctx, testUserAuthClient, "hoo", "bar", t) + // grant a new key + _, err := rootAuthClient.RoleGrantPermission(ctx, testRoleName, "hoo", "", clientv3.PermissionType(clientv3.PermReadWrite)) + require.NoError(t, err) + // try a newly granted key + require.NoError(t, testUserAuthClient.Put(ctx, "hoo", "bar", config.PutOptions{})) + // confirm put succeeded + resp, err := testUserAuthClient.Get(ctx, "hoo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "hoo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'hoo' 'bar' but got %+v", resp.Kvs) + } + // revoke the newly granted key + _, err = rootAuthClient.RoleRevokePermission(ctx, testRoleName, "hoo", "") + require.NoError(t, err) + // try put to the revoked key + putFailPerm(ctx, testUserAuthClient, "hoo", "bar", t) + // confirm a key still granted can be accessed + resp, err = testUserAuthClient.Get(ctx, "foo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "foo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'foo' 'bar' but got %+v", resp.Kvs) + } + }) +} + +func TestAuthUserDeleteDuringOps(t *testing.T) { + testRunner.BeforeTest(t) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(config.ClusterConfig{ClusterSize: 1})) + defer clus.Close() + cc := testutils.MustClient(clus.Client()) + testutils.ExecuteUntil(ctx, t, func() { + require.NoError(t, cc.Put(ctx, "foo", "bar", config.PutOptions{})) + require.NoErrorf(t, setupAuth(cc, []authRole{testRole}, []authUser{rootUser, testUser}), "failed to enable auth") + + rootAuthClient := testutils.MustClient(clus.Client(WithAuth(rootUserName, rootPassword))) + testUserAuthClient := testutils.MustClient(clus.Client(WithAuth(testUserName, testPassword))) + + // create a key + require.NoError(t, testUserAuthClient.Put(ctx, "foo", "bar", config.PutOptions{})) + // confirm put succeeded + resp, err := testUserAuthClient.Get(ctx, "foo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "foo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'foo' 'bar' but got %+v", resp.Kvs) + } + // delete the user + _, err = rootAuthClient.UserDelete(ctx, testUserName) + require.NoError(t, err) + // check the user is deleted + err = testUserAuthClient.Put(ctx, "foo", "baz", config.PutOptions{}) + if err == nil || !strings.Contains(err.Error(), rpctypes.ErrAuthFailed.Error()) { + t.Errorf("want error %s but got %v", rpctypes.ErrAuthFailed.Error(), err) + } + }) +} + +func TestAuthRoleRevokeDuringOps(t *testing.T) { + testRunner.BeforeTest(t) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(config.ClusterConfig{ClusterSize: 1})) + defer clus.Close() + cc := testutils.MustClient(clus.Client()) + testutils.ExecuteUntil(ctx, t, func() { + require.NoError(t, cc.Put(ctx, "foo", "bar", config.PutOptions{})) + require.NoErrorf(t, setupAuth(cc, []authRole{testRole}, []authUser{rootUser, testUser}), "failed to enable auth") + + rootAuthClient := testutils.MustClient(clus.Client(WithAuth(rootUserName, rootPassword))) + testUserAuthClient := testutils.MustClient(clus.Client(WithAuth(testUserName, testPassword))) + + // create a key + require.NoError(t, testUserAuthClient.Put(ctx, "foo", "bar", config.PutOptions{})) + // confirm put succeeded + resp, err := testUserAuthClient.Get(ctx, "foo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "foo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'foo' 'bar' but got %+v", resp.Kvs) + } + // create a new role + _, err = rootAuthClient.RoleAdd(ctx, "test-role2") + require.NoError(t, err) + // grant a new key to the new role + _, err = rootAuthClient.RoleGrantPermission(ctx, "test-role2", "hoo", "", clientv3.PermissionType(clientv3.PermReadWrite)) + require.NoError(t, err) + // grant the new role to the user + _, err = rootAuthClient.UserGrantRole(ctx, testUserName, "test-role2") + require.NoError(t, err) + + // try a newly granted key + require.NoError(t, testUserAuthClient.Put(ctx, "hoo", "bar", config.PutOptions{})) + // confirm put succeeded + resp, err = testUserAuthClient.Get(ctx, "hoo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "hoo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'hoo' 'bar' but got %+v", resp.Kvs) + } + // revoke a role from the user + _, err = rootAuthClient.UserRevokeRole(ctx, testUserName, testRoleName) + require.NoError(t, err) + // check the role is revoked and permission is lost from the user + putFailPerm(ctx, testUserAuthClient, "foo", "baz", t) + + // try a key that can be accessed from the remaining role + require.NoError(t, testUserAuthClient.Put(ctx, "hoo", "bar2", config.PutOptions{})) + // confirm put succeeded + resp, err = testUserAuthClient.Get(ctx, "hoo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "hoo" || string(resp.Kvs[0].Value) != "bar2" { + t.Fatalf("want key value pair 'hoo' 'bar2' but got %+v", resp.Kvs) + } + }) +} + +func putFailPerm(ctx context.Context, cc interfaces.Client, key, val string, t *testing.T) { + err := cc.Put(ctx, key, val, config.PutOptions{}) + if err == nil || !strings.Contains(err.Error(), rpctypes.ErrPermissionDenied.Error()) { + t.Errorf("want error %s but got %v", rpctypes.ErrPermissionDenied.Error(), err) + } +} + +func TestAuthWriteKey(t *testing.T) { + testRunner.BeforeTest(t) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(config.ClusterConfig{ClusterSize: 1})) + defer clus.Close() + cc := testutils.MustClient(clus.Client()) + testutils.ExecuteUntil(ctx, t, func() { + require.NoError(t, cc.Put(ctx, "foo", "a", config.PutOptions{})) + require.NoErrorf(t, setupAuth(cc, []authRole{testRole}, []authUser{rootUser, testUser}), "failed to enable auth") + + rootAuthClient := testutils.MustClient(clus.Client(WithAuth(rootUserName, rootPassword))) + testUserAuthClient := testutils.MustClient(clus.Client(WithAuth(testUserName, testPassword))) + + // confirm root role can access to all keys + require.NoError(t, rootAuthClient.Put(ctx, "foo", "bar", config.PutOptions{})) + resp, err := rootAuthClient.Get(ctx, "foo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "foo" || string(resp.Kvs[0].Value) != "bar" { + t.Fatalf("want key value pair 'foo' 'bar' but got %+v", resp.Kvs) + } + // try invalid user + _, err = clus.Client(WithAuth("a", "b")) + if err == nil || !strings.Contains(err.Error(), rpctypes.ErrAuthFailed.Error()) { + t.Errorf("want error %s but got %v", rpctypes.ErrAuthFailed.Error(), err) + } + + // try good user + require.NoError(t, testUserAuthClient.Put(ctx, "foo", "bar2", config.PutOptions{})) + // confirm put succeeded + resp, err = testUserAuthClient.Get(ctx, "foo", config.GetOptions{}) + require.NoError(t, err) + if len(resp.Kvs) != 1 || string(resp.Kvs[0].Key) != "foo" || string(resp.Kvs[0].Value) != "bar2" { + t.Fatalf("want key value pair 'foo' 'bar2' but got %+v", resp.Kvs) + } + + // try bad password + _, err = clus.Client(WithAuth(testUserName, "badpass")) + if err == nil || !strings.Contains(err.Error(), rpctypes.ErrAuthFailed.Error()) { + t.Errorf("want error %s but got %v", rpctypes.ErrAuthFailed.Error(), err) + } + }) +} + +func TestAuthTxn(t *testing.T) { + tcs := []struct { + name string + cfg config.ClusterConfig + }{ + { + "NoJWT", + config.ClusterConfig{ClusterSize: 1}, + }, + { + "JWT", + config.ClusterConfig{ClusterSize: 1, AuthToken: defaultAuthToken}, + }, + } + + reqs := []txnReq{ + { + compare: []string{`version("c2") = "1"`}, + ifSuccess: []string{"get s2"}, + ifFail: []string{"get f2"}, + results: []string{"SUCCESS", "s2", "v"}, + }, + // a key of compare case isn't granted + { + compare: []string{`version("c1") = "1"`}, + ifSuccess: []string{"get s2"}, + ifFail: []string{"get f2"}, + results: []string{"etcdserver: permission denied"}, + }, + // a key of success case isn't granted + { + compare: []string{`version("c2") = "1"`}, + ifSuccess: []string{"get s1"}, + ifFail: []string{"get f2"}, + results: []string{"etcdserver: permission denied"}, + }, + // a key of failure case isn't granted + { + compare: []string{`version("c2") = "1"`}, + ifSuccess: []string{"get s2"}, + ifFail: []string{"get f1"}, + results: []string{"etcdserver: permission denied"}, + }, + } + + for _, tc := range tcs { + t.Run(tc.name, func(t *testing.T) { + testRunner.BeforeTest(t) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + clus := testRunner.NewCluster(ctx, t, config.WithClusterConfig(tc.cfg)) + defer clus.Close() + cc := testutils.MustClient(clus.Client()) + testutils.ExecuteUntil(ctx, t, func() { + // keys with 1 suffix aren't granted to test-user + keys := []string{"c1", "s1", "f1"} + // keys with 2 suffix are granted to test-user, see Line 399 + grantedKeys := []string{"c2", "s2", "f2"} + for _, key := range keys { + if err := cc.Put(ctx, key, "v", config.PutOptions{}); err != nil { + t.Fatal(err) + } + } + for _, key := range grantedKeys { + if err := cc.Put(ctx, key, "v", config.PutOptions{}); err != nil { + t.Fatal(err) + } + } + + require.NoErrorf(t, setupAuth(cc, []authRole{testRole}, []authUser{rootUser, testUser}), "failed to enable auth") + rootAuthClient := testutils.MustClient(clus.Client(WithAuth(rootUserName, rootPassword))) + testUserAuthClient := testutils.MustClient(clus.Client(WithAuth(testUserName, testPassword))) + + // grant keys to test-user + for _, key := range grantedKeys { + if _, err := rootAuthClient.RoleGrantPermission(ctx, testRoleName, key, "", clientv3.PermissionType(clientv3.PermReadWrite)); err != nil { + t.Fatal(err) + } + } + for _, req := range reqs { + resp, err := testUserAuthClient.Txn(ctx, req.compare, req.ifSuccess, req.ifFail, config.TxnOptions{ + Interactive: true, + }) + if strings.Contains(req.results[0], "denied") { + require.Contains(t, err.Error(), req.results[0]) + } else { + require.NoError(t, err) + require.Equal(t, req.results, getRespValues(resp)) + } + } + }) + }) + } +} + +func mustAbsPath(path string) string { + abs, err := filepath.Abs(path) + if err != nil { + panic(err) + } + return abs +} diff --git a/tests/e2e/ctl_v3_auth_test.go b/tests/e2e/ctl_v3_auth_test.go index 3ac32af8e4f4..24034758208b 100644 --- a/tests/e2e/ctl_v3_auth_test.go +++ b/tests/e2e/ctl_v3_auth_test.go @@ -27,14 +27,8 @@ import ( "go.etcd.io/etcd/tests/v3/framework/e2e" ) -func TestCtlV3AuthWriteKey(t *testing.T) { testCtl(t, authCredWriteKeyTest) } -func TestCtlV3AuthRoleUpdate(t *testing.T) { testCtl(t, authRoleUpdateTest) } -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 TestCtlV3AuthTxnJWT(t *testing.T) { testCtl(t, authTestTxn, withCfg(*e2e.NewConfigJWT())) } -func TestCtlV3AuthPrefixPerm(t *testing.T) { testCtl(t, authTestPrefixPerm) } -func TestCtlV3AuthMemberAdd(t *testing.T) { testCtl(t, authTestMemberAdd) } +func TestCtlV3AuthPrefixPerm(t *testing.T) { testCtl(t, authTestPrefixPerm) } +func TestCtlV3AuthMemberAdd(t *testing.T) { testCtl(t, authTestMemberAdd) } func TestCtlV3AuthMemberRemove(t *testing.T) { testCtl(t, authTestMemberRemove, withQuorum(), withDisableStrictReconfig()) } @@ -92,218 +86,6 @@ func ctlV3AuthEnable(cx ctlCtx) error { return e2e.SpawnWithExpectWithEnv(cmdArgs, cx.envMap, "Authentication Enabled") } -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 can access to all keys - if err := ctlV3Put(cx, "foo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil { - cx.t.Fatal(err) - } - - // try invalid user - cx.user, cx.pass = "a", "b" - err := ctlV3PutFailAuth(cx, "foo", "bar") - require.ErrorContains(cx.t, err, "authentication failed") - - // 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) - } - - // try good user - cx.user, cx.pass = "test-user", "pass" - if err := ctlV3Put(cx, "foo", "bar2", ""); err != nil { - cx.t.Fatal(err) - } - // confirm put succeeded - if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil { - cx.t.Fatal(err) - } - - // try bad password - cx.user, cx.pass = "test-user", "badpass" - err = ctlV3PutFailAuth(cx, "foo", "baz") - require.ErrorContains(cx.t, err, "authentication failed") - - // confirm put failed - cx.user, cx.pass = "test-user", "pass" - if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar2"}}...); err != nil { - cx.t.Fatal(err) - } -} - -func authRoleUpdateTest(cx ctlCtx) { - if err := ctlV3Put(cx, "foo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - - if err := authEnable(cx); err != nil { - cx.t.Fatal(err) - } - - cx.user, cx.pass = "root", "root" - authSetupTestUser(cx) - - // try put to not granted key - cx.user, cx.pass = "test-user", "pass" - err := ctlV3PutFailPerm(cx, "hoo", "bar") - require.ErrorContains(cx.t, err, "permission denied") - - // grant a new key - cx.user, cx.pass = "root", "root" - if err := ctlV3RoleGrantPermission(cx, "test-role", grantingPerm{true, true, "hoo", "", false}); err != nil { - cx.t.Fatal(err) - } - - // try a newly granted key - cx.user, cx.pass = "test-user", "pass" - if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - // confirm put succeeded - if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil { - cx.t.Fatal(err) - } - - // revoke the newly granted key - cx.user, cx.pass = "root", "root" - if err := ctlV3RoleRevokePermission(cx, "test-role", "hoo", "", false); err != nil { - cx.t.Fatal(err) - } - - // try put to the revoked key - cx.user, cx.pass = "test-user", "pass" - err = ctlV3PutFailPerm(cx, "hoo", "bar") - require.ErrorContains(cx.t, err, "permission denied") - - // confirm a key still granted can be accessed - if err := ctlV3Get(cx, []string{"foo"}, []kv{{"foo", "bar"}}...); err != nil { - cx.t.Fatal(err) - } -} - -func authUserDeleteDuringOpsTest(cx ctlCtx) { - if err := ctlV3Put(cx, "foo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - - if err := authEnable(cx); err != nil { - cx.t.Fatal(err) - } - - cx.user, cx.pass = "root", "root" - authSetupTestUser(cx) - - // create a key - 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) - } - - // delete the user - cx.user, cx.pass = "root", "root" - err := ctlV3User(cx, []string{"delete", "test-user"}, "User test-user deleted", []string{}) - if err != nil { - cx.t.Fatal(err) - } - - // check the user is deleted - cx.user, cx.pass = "test-user", "pass" - err = ctlV3PutFailAuth(cx, "foo", "baz") - require.ErrorContains(cx.t, err, "authentication failed") -} - -func authRoleRevokeDuringOpsTest(cx ctlCtx) { - if err := ctlV3Put(cx, "foo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - - if err := authEnable(cx); err != nil { - cx.t.Fatal(err) - } - - cx.user, cx.pass = "root", "root" - authSetupTestUser(cx) - - // create a key - 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) - } - - // create a new role - cx.user, cx.pass = "root", "root" - if err := ctlV3Role(cx, []string{"add", "test-role2"}, "Role test-role2 created"); err != nil { - cx.t.Fatal(err) - } - // grant a new key to the new role - if err := ctlV3RoleGrantPermission(cx, "test-role2", grantingPerm{true, true, "hoo", "", false}); err != nil { - cx.t.Fatal(err) - } - // grant the new role to the user - if err := ctlV3User(cx, []string{"grant-role", "test-user", "test-role2"}, "Role test-role2 is granted to user test-user", nil); err != nil { - cx.t.Fatal(err) - } - - // try a newly granted key - cx.user, cx.pass = "test-user", "pass" - if err := ctlV3Put(cx, "hoo", "bar", ""); err != nil { - cx.t.Fatal(err) - } - // confirm put succeeded - if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar"}}...); err != nil { - cx.t.Fatal(err) - } - - // revoke a role from the user - cx.user, cx.pass = "root", "root" - err := ctlV3User(cx, []string{"revoke-role", "test-user", "test-role"}, "Role test-role is revoked from user test-user", []string{}) - if err != nil { - cx.t.Fatal(err) - } - - // check the role is revoked and permission is lost from the user - cx.user, cx.pass = "test-user", "pass" - err = ctlV3PutFailPerm(cx, "foo", "baz") - require.ErrorContains(cx.t, err, "permission denied") - - // try a key that can be accessed from the remaining role - cx.user, cx.pass = "test-user", "pass" - if err := ctlV3Put(cx, "hoo", "bar2", ""); err != nil { - cx.t.Fatal(err) - } - // confirm put succeeded - if err := ctlV3Get(cx, []string{"hoo"}, []kv{{"hoo", "bar2"}}...); err != nil { - cx.t.Fatal(err) - } -} - -func ctlV3PutFailAuth(cx ctlCtx, key, val string) error { - return e2e.SpawnWithExpectWithEnv(append(cx.PrefixArgs(), "put", key, val), cx.envMap, "authentication failed") -} - func ctlV3PutFailPerm(cx ctlCtx, key, val string) error { return e2e.SpawnWithExpectWithEnv(append(cx.PrefixArgs(), "put", key, val), cx.envMap, "permission denied") } @@ -324,87 +106,6 @@ func authSetupTestUser(cx ctlCtx) { } } -func authTestTxn(cx ctlCtx) { - // keys with 1 suffix aren't granted to test-user - // keys with 2 suffix are granted to test-user - - keys := []string{"c1", "s1", "f1"} - grantedKeys := []string{"c2", "s2", "f2"} - for _, key := range keys { - if err := ctlV3Put(cx, key, "v", ""); err != nil { - cx.t.Fatal(err) - } - } - - for _, key := range grantedKeys { - if err := ctlV3Put(cx, key, "v", ""); err != nil { - cx.t.Fatal(err) - } - } - - if err := authEnable(cx); err != nil { - cx.t.Fatal(err) - } - - cx.user, cx.pass = "root", "root" - authSetupTestUser(cx) - - // 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, "", false}); err != nil { - cx.t.Fatal(err) - } - } - - // now test txn - cx.interactive = true - cx.user, cx.pass = "test-user", "pass" - - rqs := txnRequests{ - compare: []string{`version("c2") = "1"`}, - ifSuccess: []string{"get s2"}, - ifFail: []string{"get f2"}, - results: []string{"SUCCESS", "s2", "v"}, - } - if err := ctlV3Txn(cx, rqs, false); err != nil { - cx.t.Fatal(err) - } - - // a key of compare case isn't granted - rqs = txnRequests{ - compare: []string{`version("c1") = "1"`}, - ifSuccess: []string{"get s2"}, - ifFail: []string{"get f2"}, - results: []string{"Error: etcdserver: permission denied"}, - } - if err := ctlV3Txn(cx, rqs, true); err != nil { - cx.t.Fatal(err) - } - - // a key of success case isn't granted - rqs = txnRequests{ - compare: []string{`version("c2") = "1"`}, - ifSuccess: []string{"get s1"}, - ifFail: []string{"get f2"}, - results: []string{"Error: etcdserver: permission denied"}, - } - if err := ctlV3Txn(cx, rqs, true); err != nil { - cx.t.Fatal(err) - } - - // a key of failure case isn't granted - rqs = txnRequests{ - compare: []string{`version("c2") = "1"`}, - ifSuccess: []string{"get s2"}, - ifFail: []string{"get f1"}, - results: []string{"Error: etcdserver: permission denied"}, - } - if err := ctlV3Txn(cx, rqs, true); err != nil { - cx.t.Fatal(err) - } -} - func authTestPrefixPerm(cx ctlCtx) { if err := authEnable(cx); err != nil { cx.t.Fatal(err)