[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 <ivan@synadia.com>
This commit is contained in:
Ivan Kozlovic
2021-06-21 14:02:52 -06:00
parent 6129562b63
commit a39b549513
2 changed files with 55 additions and 8 deletions

View File

@@ -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
}
}

View File

@@ -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
}
}