From 7e174f4fb202cdc7b0cd32b75aefc35617360b82 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Fri, 10 Apr 2026 13:40:22 +0530 Subject: [PATCH 1/4] fix(server): preserve existing connections after requirepass changes --- src/server/redis_connection.cc | 4 ++++ tests/gocase/unit/auth/auth_test.go | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc index f9db92b0ce9..43d1be87441 100644 --- a/src/server/redis_connection.cc +++ b/src/server/redis_connection.cc @@ -52,6 +52,10 @@ Connection::Connection(bufferevent *bev, Worker *owner) int64_t now = util::GetTimeStamp(); create_time_ = now; last_interaction_ = now; + if (srv_->GetConfig()->requirepass.empty()) { + BecomeAdmin(); + SetNamespace(kDefaultNamespace); + } } Connection::~Connection() { diff --git a/tests/gocase/unit/auth/auth_test.go b/tests/gocase/unit/auth/auth_test.go index 562281487e9..ebfdbf5ad5c 100644 --- a/tests/gocase/unit/auth/auth_test.go +++ b/tests/gocase/unit/auth/auth_test.go @@ -39,6 +39,22 @@ func TestNoAuth(t *testing.T) { r := rdb.Do(ctx, "AUTH", "foo") require.ErrorContains(t, r.Err(), "no password") }) + + t.Run("Connections accepted before requirepass is set remain usable", func(t *testing.T) { + idleConn := srv.NewTCPClient() + defer func() { require.NoError(t, idleConn.Close()) }() + + require.NoError(t, rdb.ConfigSet(ctx, "requirepass", "foobar").Err()) + + require.NoError(t, idleConn.WriteArgs("PING")) + idleConn.MustRead(t, "+PONG") + + newConn := srv.NewTCPClient() + defer func() { require.NoError(t, newConn.Close()) }() + + require.NoError(t, newConn.WriteArgs("PING")) + newConn.MustRead(t, "-NOAUTH Authentication required.") + }) } func TestAuth(t *testing.T) { From bb21e048e06ca26784cd0cd50543ce5f6be2d095 Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Fri, 10 Apr 2026 18:30:14 +0530 Subject: [PATCH 2/4] fix(server): initialize passwordless auth on accept --- src/server/redis_connection.cc | 4 ---- src/server/redis_connection.h | 1 + src/server/worker.cc | 8 ++++++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc index 43d1be87441..f9db92b0ce9 100644 --- a/src/server/redis_connection.cc +++ b/src/server/redis_connection.cc @@ -52,10 +52,6 @@ Connection::Connection(bufferevent *bev, Worker *owner) int64_t now = util::GetTimeStamp(); create_time_ = now; last_interaction_ = now; - if (srv_->GetConfig()->requirepass.empty()) { - BecomeAdmin(); - SetNamespace(kDefaultNamespace); - } } Connection::~Connection() { diff --git a/src/server/redis_connection.h b/src/server/redis_connection.h index 4eba076e67a..7e339cec3c0 100644 --- a/src/server/redis_connection.h +++ b/src/server/redis_connection.h @@ -154,6 +154,7 @@ class Connection : public EvbufCallbackBase { bool IsAdmin() const { return is_admin_; } void BecomeAdmin() { is_admin_ = true; } void BecomeUser() { is_admin_ = false; } + void InitDefaultNamespace() { SetNamespace(kDefaultNamespace); } std::string GetNamespace() const { return ns_; } void SetNamespace(std::string ns) { ns_ = std::move(ns); } diff --git a/src/server/worker.cc b/src/server/worker.cc index 45eceb70577..9cfaf8d1327 100644 --- a/src/server/worker.cc +++ b/src/server/worker.cc @@ -176,6 +176,10 @@ void Worker::newTCPConnection(evconnlistener *listener, evutil_socket_t fd, [[ma } #endif auto conn = new redis::Connection(bev, this); + if (srv->GetConfig()->requirepass.empty()) { + conn->BecomeAdmin(); + conn->InitDefaultNamespace(); + } conn->SetCB(bev); bufferevent_enable(bev, EV_READ); @@ -210,6 +214,10 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f bufferevent *bev = bufferevent_socket_new(base, fd, ev_thread_safe_flags); auto conn = new redis::Connection(bev, this); + if (srv->GetConfig()->requirepass.empty()) { + conn->BecomeAdmin(); + conn->InitDefaultNamespace(); + } conn->SetCB(bev); bufferevent_enable(bev, EV_READ); From 3075404d2f82cc25a7196f3ea3ff76d553ea00ab Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Thu, 16 Apr 2026 20:50:19 +0530 Subject: [PATCH 3/4] fix(tests): wait for accepted auth connection in regression --- tests/gocase/unit/auth/auth_test.go | 12 ++++++++++++ tests/gocase/util/tcp_client.go | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/tests/gocase/unit/auth/auth_test.go b/tests/gocase/unit/auth/auth_test.go index ebfdbf5ad5c..ff5f5f37d05 100644 --- a/tests/gocase/unit/auth/auth_test.go +++ b/tests/gocase/unit/auth/auth_test.go @@ -21,7 +21,11 @@ package auth import ( "context" + "fmt" + "net" + "regexp" "testing" + "time" "github.com/apache/kvrocks/tests/gocase/util" "github.com/stretchr/testify/require" @@ -44,6 +48,14 @@ func TestNoAuth(t *testing.T) { idleConn := srv.NewTCPClient() defer func() { require.NoError(t, idleConn.Close()) }() + _, idlePort, err := net.SplitHostPort(idleConn.LocalAddr().String()) + require.NoError(t, err) + + idleConnPattern := regexp.MustCompile(fmt.Sprintf(`(?:^| )addr=[^ ]*:%s(?: |$)`, idlePort)) + require.Eventually(t, func() bool { + return idleConnPattern.MatchString(rdb.ClientList(ctx).Val()) + }, 5*time.Second, 10*time.Millisecond) + require.NoError(t, rdb.ConfigSet(ctx, "requirepass", "foobar").Err()) require.NoError(t, idleConn.WriteArgs("PING")) diff --git a/tests/gocase/util/tcp_client.go b/tests/gocase/util/tcp_client.go index 3cd9de2b1a9..dfc0f6cbcfd 100644 --- a/tests/gocase/util/tcp_client.go +++ b/tests/gocase/util/tcp_client.go @@ -59,6 +59,10 @@ func (c *TCPClient) Close() error { return c.c.Close() } +func (c *TCPClient) LocalAddr() net.Addr { + return c.c.LocalAddr() +} + func (c *TCPClient) ReadLine() (string, error) { r, err := c.r.ReadString('\n') if err != nil { From 46a0bf9dd3dbffc807de326b95398e29a49ce91e Mon Sep 17 00:00:00 2001 From: aviralgarg05 Date: Fri, 17 Apr 2026 12:03:50 +0530 Subject: [PATCH 4/4] fix(server): publish initialized client connections --- src/server/worker.cc | 10 +++++----- .../gocase/integration/replication/replication_test.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/server/worker.cc b/src/server/worker.cc index 9cfaf8d1327..c36c84ff9dd 100644 --- a/src/server/worker.cc +++ b/src/server/worker.cc @@ -183,6 +183,11 @@ void Worker::newTCPConnection(evconnlistener *listener, evutil_socket_t fd, [[ma conn->SetCB(bev); bufferevent_enable(bev, EV_READ); + if (auto s = util::GetPeerAddr(fd)) { + auto [ip, port] = std::move(*s); + conn->SetAddr(ip, port); + } + s = AddConnection(conn); if (!s.IsOK()) { std::string err_msg = redis::Error({Status::NotOK, s.Msg()}); @@ -194,11 +199,6 @@ void Worker::newTCPConnection(evconnlistener *listener, evutil_socket_t fd, [[ma return; } - if (auto s = util::GetPeerAddr(fd)) { - auto [ip, port] = std::move(*s); - conn->SetAddr(ip, port); - } - if (rate_limit_group_) { bufferevent_add_to_rate_limit_group(bev, rate_limit_group_); } diff --git a/tests/gocase/integration/replication/replication_test.go b/tests/gocase/integration/replication/replication_test.go index 6e291ecc590..9b8f900eccb 100644 --- a/tests/gocase/integration/replication/replication_test.go +++ b/tests/gocase/integration/replication/replication_test.go @@ -329,7 +329,7 @@ func TestReplicationWithLimitSpeed(t *testing.T) { require.Eventually(t, func() bool { return slave.LogFileMatches(t, ".*skip count: 1.*") }, 50*time.Second, 1000*time.Millisecond) - util.WaitForSync(t, slaveClient) + util.WaitForOffsetSync(t, masterClient, slaveClient, 50*time.Second) require.Equal(t, "b", slaveClient.Get(ctx, "a").Val()) }) }