diff --git a/server/auth_test.go b/server/auth_test.go index 65cc6fcb..943d7711 100644 --- a/server/auth_test.go +++ b/server/auth_test.go @@ -15,11 +15,13 @@ package server import ( "fmt" + "net" "net/url" "os" "reflect" "strings" "testing" + "time" "github.com/nats-io/jwt/v2" "github.com/nats-io/nats.go" @@ -273,3 +275,46 @@ func TestNoAuthUser(t *testing.T) { }) } } + +func TestNoAuthUserNoConnectProto(t *testing.T) { + conf := createConfFile(t, []byte(` + listen: "127.0.0.1:-1" + accounts { + A { users [{user: "foo", password: "pwd"}] } + } + authorization { timeout: 1s } + no_auth_user: "foo" + `)) + defer os.Remove(conf) + s, o := RunServerWithConfig(conf) + defer s.Shutdown() + + checkClients := func(n int) { + t.Helper() + time.Sleep(100 * time.Millisecond) + if nc := s.NumClients(); nc != n { + t.Fatalf("Expected %d clients, got %d", n, nc) + } + } + + conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port)) + require_NoError(t, err) + defer conn.Close() + checkClientsCount(t, s, 1) + + // With no auth user we should not require a CONNECT. + // Make sure we are good on not sending CONN first. + _, err = conn.Write([]byte("PUB foo 2\r\nok\r\n")) + require_NoError(t, err) + checkClients(1) + conn.Close() + + // Now make sure we still do get timed out though. + conn, err = net.Dial("tcp", fmt.Sprintf("%s:%d", o.Host, o.Port)) + require_NoError(t, err) + defer conn.Close() + checkClientsCount(t, s, 1) + + time.Sleep(1200 * time.Millisecond) + checkClientsCount(t, s, 0) +} diff --git a/server/parser.go b/server/parser.go index a9c3533a..7bd9182d 100644 --- a/server/parser.go +++ b/server/parser.go @@ -147,8 +147,7 @@ func (c *client) parse(buf []byte) error { // proper CONNECT if needed. authSet := c.awaitingAuth() // Snapshot max control line as well. - mcl := c.mcl - trace := c.trace + s, mcl, trace := c.srv, c.mcl, c.trace c.mu.Unlock() // Move to loop instead of range syntax to allow jumping of i @@ -160,7 +159,24 @@ func (c *client) parse(buf []byte) error { c.op = b if b != 'C' && b != 'c' { if authSet { - goto authErr + if s == nil { + goto authErr + } + var ok bool + // Check here for NoAuthUser. If this is set allow non CONNECT protos as our first. + // E.g. telnet proto demos. + if noAuthUser := s.getOpts().NoAuthUser; noAuthUser != _EMPTY_ { + s.mu.Lock() + user, exists := s.users[noAuthUser] + s.mu.Unlock() + if exists { + c.RegisterUser(user) + ok = true + } + } + if !ok { + goto authErr + } } // If the connection is a gateway connection, make sure that // if this is an inbound, it starts with a CONNECT.