From a39b549513c6f7c93f8840c2cf86d0f44ad90cbe Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Mon, 21 Jun 2021 14:02:52 -0600 Subject: [PATCH] [FIXED] Clients disconnected on reload when only $SYS account configured This was introduced by PR#1900 by detecting that a single system account was configured. A "fake" user name was created and added to the list of users and set as a no_auth_user. However, on config reload, a new fake user was created, which would cause existing connected clients to be disconnected. Resolves #2282 Signed-off-by: Ivan Kozlovic --- server/reload_test.go | 36 ++++++++++++++++++++++++++++++++++++ server/server.go | 27 +++++++++++++++++++-------- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/server/reload_test.go b/server/reload_test.go index aadcce82..eb5fb7d7 100644 --- a/server/reload_test.go +++ b/server/reload_test.go @@ -4522,3 +4522,39 @@ func TestConfigReloadAccountMappings(t *testing.T) { checkPending(fsub, 1) checkPending(sub, 0) } + +func TestConfigReloadWithSysAccountOnly(t *testing.T) { + conf := createConfFile(t, []byte(` + listen: "127.0.0.1:-1" + accounts { + $SYS { + users = [{user: "system",pass: "password"}, {user: "system2",pass: "password2"}] + } + } + `)) + defer os.Remove(conf) + s, _ := RunServerWithConfig(conf) + defer s.Shutdown() + + dch := make(chan struct{}, 1) + nc := natsConnect(t, + s.ClientURL(), + nats.DisconnectErrHandler(func(_ *nats.Conn, _ error) { + dch <- struct{}{} + }), + nats.NoCallbacksAfterClientClose()) + defer nc.Close() + + // Just reload... + if err := s.Reload(); err != nil { + t.Fatalf("Error on reload: %v", err) + } + + // Make sure we did not get disconnected + select { + case <-dch: + t.Fatal("Got disconnected!") + case <-time.After(500 * time.Millisecond): + // ok + } +} diff --git a/server/server.go b/server/server.go index cca7e77c..f5220961 100644 --- a/server/server.go +++ b/server/server.go @@ -256,6 +256,11 @@ type Server struct { // For out of resources to not log errors too fast. rerrMu sync.Mutex rerrLast time.Time + + // If there is a system account configured, to still support the $G account, + // the server will create a fake user and add it to the list of users. + // Keep track of what that user name is for config reload purposes. + sysAccOnlyNoAuthUser string } type nodeInfo struct { @@ -756,15 +761,21 @@ func (s *Server) configureAccounts() error { // We would do this to add user/pass to the system account. If this is the case add in // no-auth-user for $G. if numAccounts == 2 && s.opts.NoAuthUser == _EMPTY_ { - // Create a unique name so we do not collide. - var b [8]byte - rn := rand.Int63() - for i, l := 0, rn; i < len(b); i++ { - b[i] = digits[l%base] - l /= base + // If we come here from config reload, let's not recreate the fake user name otherwise + // it will cause currently clients to be disconnected. + uname := s.sysAccOnlyNoAuthUser + if uname == _EMPTY_ { + // Create a unique name so we do not collide. + var b [8]byte + rn := rand.Int63() + for i, l := 0, rn; i < len(b); i++ { + b[i] = digits[l%base] + l /= base + } + uname = fmt.Sprintf("nats-%s", b[:]) + s.sysAccOnlyNoAuthUser = uname } - uname := fmt.Sprintf("nats-%s", b[:]) - s.opts.Users = append(s.opts.Users, &User{Username: uname, Password: string(b[:]), Account: s.gacc}) + s.opts.Users = append(s.opts.Users, &User{Username: uname, Password: uname[6:], Account: s.gacc}) s.opts.NoAuthUser = uname } }