From 90585e03a0c4b935fc4c4f4363981908a3f98be3 Mon Sep 17 00:00:00 2001 From: Benjamin Wang Date: Thu, 17 Nov 2022 08:47:51 +0800 Subject: [PATCH] test: add test case to cover the CommonName based authentication Signed-off-by: Benjamin Wang --- tests/e2e/ctl_v3_auth_no_proxy_test.go | 108 +++++++++++++++++++++++++ tests/e2e/ctl_v3_auth_test.go | 23 ++++++ 2 files changed, 131 insertions(+) diff --git a/tests/e2e/ctl_v3_auth_no_proxy_test.go b/tests/e2e/ctl_v3_auth_no_proxy_test.go index e6d53e2f3..58ead6e9b 100644 --- a/tests/e2e/ctl_v3_auth_no_proxy_test.go +++ b/tests/e2e/ctl_v3_auth_no_proxy_test.go @@ -14,12 +14,18 @@ // These tests depends on certificate-based authentication that is NOT supported // by gRPC proxy. +//go:build !cluster_proxy // +build !cluster_proxy package e2e import ( + "fmt" + "sync" "testing" + "time" + + "go.etcd.io/etcd/pkg/testutil" ) func TestCtlV3AuthCertCN(t *testing.T) { @@ -31,3 +37,105 @@ func TestCtlV3AuthCertCNAndUsername(t *testing.T) { func TestCtlV3AuthCertCNAndUsernameNoPassword(t *testing.T) { testCtl(t, authTestCertCNAndUsernameNoPassword, withCfg(configClientTLSCertAuth)) } + +func TestCtlV3AuthCertCNWithWithConcurrentOperation(t *testing.T) { + defer testutil.AfterTest(t) + + // apply the certificate which has `root` CommonName, + // and reset the setting when the test case finishes. + // TODO(ahrtr): enhance the e2e test framework to support + // certificates with CommonName. + t.Log("Apply certificate with root CommonName") + resetCert := applyTLSWithRootCommonName() + defer resetCert() + + t.Log("Create an etcd cluster") + cx := getDefaultCtlCtx(t) + cx.cfg = etcdProcessClusterConfig{ + clusterSize: 1, + clientTLS: clientTLS, + clientCertAuthEnabled: true, + initialToken: "new", + } + + epc, err := newEtcdProcessCluster(&cx.cfg) + if err != nil { + t.Fatalf("Failed to start etcd cluster: %v", err) + } + cx.epc = epc + + defer func() { + if err := epc.Close(); err != nil { + t.Fatalf("could not close test cluster (%v)", err) + } + }() + + t.Log("Enable auth") + authEnableTest(cx) + + // Create two goroutines, one goroutine keeps creating & deleting users, + // and the other goroutine keeps writing & deleting K/V entries. + var wg sync.WaitGroup + wg.Add(2) + errs := make(chan error, 2) + donec := make(chan struct{}) + + // Create the first goroutine to create & delete users + t.Log("Create the first goroutine to create & delete users") + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + user := fmt.Sprintf("testuser-%d", i) + pass := fmt.Sprintf("testpass-%d", i) + + if err := ctlV3User(cx, []string{"add", user, "--interactive=false"}, fmt.Sprintf("User %s created", user), []string{pass}); err != nil { + errs <- fmt.Errorf("failed to create user %q: %w", user, err) + break + } + + err := ctlV3User(cx, []string{"delete", user}, fmt.Sprintf("User %s deleted", user), []string{}) + if err != nil { + errs <- fmt.Errorf("failed to delete user %q: %w", user, err) + break + } + } + t.Log("The first goroutine finished") + }() + + // Create the second goroutine to write & delete K/V entries + t.Log("Create the second goroutine to write & delete K/V entries") + go func() { + defer wg.Done() + for i := 0; i < 100; i++ { + key := fmt.Sprintf("key-%d", i) + value := fmt.Sprintf("value-%d", i) + + if err := ctlV3Put(cx, key, value, ""); err != nil { + errs <- fmt.Errorf("failed to put key %q: %w", key, err) + break + } + + if err := ctlV3Del(cx, []string{key}, 1); err != nil { + errs <- fmt.Errorf("failed to delete key %q: %w", key, err) + break + } + } + t.Log("The second goroutine finished") + }() + + t.Log("Waiting for the two goroutines to complete") + go func() { + wg.Wait() + close(donec) + }() + + t.Log("Waiting for test result") + select { + case err := <-errs: + t.Fatalf("Unexpected error: %v", err) + case <-donec: + t.Log("All done!") + case <-time.After(60 * time.Second): + t.Fatal("Test case timeout after 60 seconds") + } +} diff --git a/tests/e2e/ctl_v3_auth_test.go b/tests/e2e/ctl_v3_auth_test.go index 979292e92..036721491 100644 --- a/tests/e2e/ctl_v3_auth_test.go +++ b/tests/e2e/ctl_v3_auth_test.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "os" + "path/filepath" "syscall" "testing" "time" @@ -74,6 +75,28 @@ func authEnableTest(cx ctlCtx) { } } +func applyTLSWithRootCommonName() func() { + var ( + oldCertPath = certPath + oldPrivateKeyPath = privateKeyPath + oldCaPath = caPath + + newCertPath = filepath.Join(certDir, "CommonName-root.crt") + newPrivateKeyPath = filepath.Join(certDir, "CommonName-root.key") + newCaPath = filepath.Join(certDir, "CommonName-root.crt") + ) + + certPath = newCertPath + privateKeyPath = newPrivateKeyPath + caPath = newCaPath + + return func() { + certPath = oldCertPath + privateKeyPath = oldPrivateKeyPath + caPath = oldCaPath + } +} + 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 {