From 3d29138f98eed1b8e9abac513cb002c88eb15bc5 Mon Sep 17 00:00:00 2001 From: vivekpatani <9080894+vivekpatani@users.noreply.github.com> Date: Mon, 22 Aug 2022 14:33:10 -0700 Subject: [PATCH] server,test: refresh cache on each NewAuthStore - permissions were incorrectly loaded on restarts. - https://github.com/etcd-io/etcd/issues/14355 Signed-off-by: vivekpatani <9080894+vivekpatani@users.noreply.github.com> --- server/auth/store.go | 2 + tests/e2e/ctl_v3_auth_test.go | 90 +++++++++++++++++++++++++++++++ tests/integration/v3_auth_test.go | 73 +++++++++++++++++++++++++ 3 files changed, 165 insertions(+) diff --git a/server/auth/store.go b/server/auth/store.go index 370629c29a28..e481db88e2d1 100644 --- a/server/auth/store.go +++ b/server/auth/store.go @@ -965,6 +965,8 @@ func NewAuthStore(lg *zap.Logger, be AuthBackend, tp TokenProvider, bcryptCost i as.setupMetricsReporter() + as.refreshRangePermCache(tx) + tx.Unlock() be.ForceCommit() diff --git a/tests/e2e/ctl_v3_auth_test.go b/tests/e2e/ctl_v3_auth_test.go index 8c9980049dfd..143e7ad3163a 100644 --- a/tests/e2e/ctl_v3_auth_test.go +++ b/tests/e2e/ctl_v3_auth_test.go @@ -77,6 +77,8 @@ func TestCtlV3AuthJWTExpire(t *testing.T) { } func TestCtlV3AuthRevisionConsistency(t *testing.T) { testCtl(t, authTestRevisionConsistency) } +func TestCtlV3AuthTestCacheReload(t *testing.T) { testCtl(t, authTestCacheReload) } + func authEnableTest(cx ctlCtx) { if err := authEnable(cx); err != nil { cx.t.Fatal(err) @@ -1326,3 +1328,91 @@ func ctlV3User(cx ctlCtx, args []string, expStr string, stdIn []string) error { _, err = proc.Expect(expStr) return err } + +// authTestCacheReload tests the permissions when a member restarts +func authTestCacheReload(cx ctlCtx) { + + rootUser := "root" + rootRole := "root" + rootPass := "123" + + nonRootUser := "user0" + nonRootRole := "role0" + nonRootPass := "123" + + node0 := cx.epc.Procs[0] + endpoint := node0.EndpointsV3()[0] + + // create a client + c, err := clientv3.New(clientv3.Config{Endpoints: []string{endpoint}, DialTimeout: 3 * time.Second}) + if err != nil { + cx.t.Fatal(err) + } + defer c.Close() + + // add a root role + _, err = c.RoleAdd(context.TODO(), rootRole) + if err != nil { + cx.t.Fatal(err) + } + // add a user root + _, err = c.UserAdd(context.TODO(), rootUser, rootPass) + if err != nil { + cx.t.Fatal(err) + } + // grant root role to root user + _, err = c.UserGrantRole(context.TODO(), rootUser, rootRole) + if err != nil { + cx.t.Fatal(err) + } + + // add a role0 role + _, err = c.RoleAdd(context.TODO(), nonRootRole) + if err != nil { + cx.t.Fatal(err) + } + // role grant permission to role0 + _, err = c.RoleGrantPermission(context.TODO(), nonRootRole, "foo", "", clientv3.PermissionType(clientv3.PermReadWrite)) + if err != nil { + cx.t.Fatal(err) + } + // add a user user0 + _, err = c.UserAdd(context.TODO(), nonRootUser, nonRootPass) + if err != nil { + cx.t.Fatal(err) + } + // grant that user the role0 to user0 + _, err = c.UserGrantRole(context.TODO(), nonRootUser, nonRootRole) + if err != nil { + cx.t.Fatal(err) + } + + // enable auth + _, err = c.AuthEnable(context.TODO()) + if err != nil { + cx.t.Fatal(err) + } + + // create another client with ID:Password + c2, err := clientv3.New(clientv3.Config{Endpoints: []string{endpoint}, Username: nonRootUser, Password: nonRootPass, DialTimeout: 3 * time.Second}) + defer c2.Close() + + // create foo since that is within the permission set + // expectation is to succeed + _, err = c2.Put(context.TODO(), "foo", "bar") + if err != nil { + cx.t.Fatal(err) + } + + // restart the node + node0.WithStopSignal(syscall.SIGINT) + if err := node0.Restart(); err != nil { + cx.t.Fatal(err) + } + + // nothing has changed, but it fails without refreshing cache after restart + _, err = c2.Put(context.TODO(), "foo", "bar2") + if err != nil { + cx.t.Fatal(err) + } +} diff --git a/tests/integration/v3_auth_test.go b/tests/integration/v3_auth_test.go index 9f644572ed77..3a1815416b22 100644 --- a/tests/integration/v3_auth_test.go +++ b/tests/integration/v3_auth_test.go @@ -421,3 +421,76 @@ func TestV3AuthOldRevConcurrent(t *testing.T) { } wg.Wait() } + +func TestV3AuthRestartMember(t *testing.T) { + integration.BeforeTest(t) + + rootUser := "root" + rootRole := "root" + rootPass := "123" + + nonRootUser := "user0" + nonRootRole := "role0" + nonRootPass := "123" + + // create a cluster with 1 member + clus := integration.NewCluster(t, &integration.ClusterConfig{Size: 1}) + defer clus.Terminate(t) + + // create a client + c, cerr := integration.NewClient(t, clientv3.Config{ + Endpoints: clus.Client(0).Endpoints(), + DialTimeout: 5 * time.Second, + }) + testutil.AssertNil(t, cerr) + defer c.Close() + + // add a root role + _, err := c.RoleAdd(context.TODO(), rootRole) + testutil.AssertNil(t, err) + // add a user root + _, err = c.UserAdd(context.TODO(), rootUser, rootPass) + testutil.AssertNil(t, err) + // grant root role to root user + _, err = c.UserGrantRole(context.TODO(), rootUser, rootRole) + testutil.AssertNil(t, err) + + // add a role0 role + _, err = c.RoleAdd(context.TODO(), nonRootRole) + testutil.AssertNil(t, err) + // role grant permission to role0 + _, err = c.RoleGrantPermission(context.TODO(), nonRootRole, "foo", "", clientv3.PermissionType(clientv3.PermReadWrite)) + testutil.AssertNil(t, err) + // add a user user0 + _, err = c.UserAdd(context.TODO(), nonRootUser, nonRootPass) + testutil.AssertNil(t, err) + // grant that user the role0 to user0 + _, err = c.UserGrantRole(context.TODO(), nonRootUser, nonRootRole) + testutil.AssertNil(t, err) + + // enable auth + _, err = c.AuthEnable(context.TODO()) + testutil.AssertNil(t, err) + + // create another client with ID:Password + c2, cerr := integration.NewClient(t, clientv3.Config{ + Endpoints: clus.Client(0).Endpoints(), + DialTimeout: 5 * time.Second, + Username: nonRootUser, + Password: nonRootPass, + }) + defer c2.Close() + + // create foo since that is within the permission set + // expectation is to succeed + _, err = c2.Put(context.TODO(), "foo", "bar") + testutil.AssertNil(t, err) + + clus.Members[0].Stop(t) + err = clus.Members[0].Restart(t) + testutil.AssertNil(t, err) + + // nothing has changed, but it fails without refreshing cache after restart + _, err = c2.Put(context.TODO(), "foo", "bar2") + testutil.AssertNil(t, err) +}