From 04f96813a7a09fecae76cbddc4ac0ff27c6cd497 Mon Sep 17 00:00:00 2001 From: Ivan Kozlovic Date: Fri, 18 Sep 2020 13:09:52 -0600 Subject: [PATCH] Validate options for user embedded NATS Server in their app We were doing option validation from options parsing, but added it also for Users/NKeyUsers options. Signed-off-by: Ivan Kozlovic --- server/auth.go | 26 ++++++++++++++++++++++ server/auth_test.go | 53 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/server/auth.go b/server/auth.go index a675ccfb..14eff310 100644 --- a/server/auth.go +++ b/server/auth.go @@ -922,9 +922,35 @@ func comparePasswords(serverPassword, clientPassword string) bool { } func validateAuth(o *Options) error { + for _, u := range o.Users { + if err := validateAllowedConnectionTypes(u.AllowedConnectionTypes); err != nil { + return err + } + } + for _, u := range o.Nkeys { + if err := validateAllowedConnectionTypes(u.AllowedConnectionTypes); err != nil { + return err + } + } return validateNoAuthUser(o, o.NoAuthUser) } +func validateAllowedConnectionTypes(m map[string]struct{}) error { + for ct := range m { + ctuc := strings.ToUpper(ct) + switch ctuc { + case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket, jwt.ConnectionTypeLeafnode: + default: + return fmt.Errorf("unknown connection type %q", ct) + } + if ctuc != ct { + delete(m, ct) + m[ctuc] = struct{}{} + } + } + return nil +} + func validateNoAuthUser(o *Options, noAuthUser string) error { if noAuthUser == "" { return nil diff --git a/server/auth_test.go b/server/auth_test.go index a0bc7920..031c70ec 100644 --- a/server/auth_test.go +++ b/server/auth_test.go @@ -15,7 +15,10 @@ package server import ( "reflect" + "strings" "testing" + + "github.com/nats-io/jwt/v2" ) func TestUserCloneNilPermissions(t *testing.T) { @@ -101,3 +104,53 @@ func TestUserCloneNil(t *testing.T) { t.Fatalf("Expected nil, got: %+v", clone) } } + +func TestUserUnknownAllowedConnectionType(t *testing.T) { + o := DefaultOptions() + o.Users = []*User{&User{ + Username: "user", + Password: "pwd", + AllowedConnectionTypes: testCreateAllowedConnectionTypes([]string{jwt.ConnectionTypeStandard, "someNewType"}), + }} + _, err := NewServer(o) + if err == nil || !strings.Contains(err.Error(), "connection type") { + t.Fatalf("Expected error about unknown connection type, got %v", err) + } + + o.Users[0].AllowedConnectionTypes = testCreateAllowedConnectionTypes([]string{"websocket"}) + s, err := NewServer(o) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + s.mu.Lock() + user := s.opts.Users[0] + s.mu.Unlock() + for act := range user.AllowedConnectionTypes { + if act != jwt.ConnectionTypeWebsocket { + t.Fatalf("Expected map to have been updated with proper case, got %v", act) + } + } + // Same with NKey user now. + o.Users = nil + o.Nkeys = []*NkeyUser{&NkeyUser{ + Nkey: "somekey", + AllowedConnectionTypes: testCreateAllowedConnectionTypes([]string{jwt.ConnectionTypeStandard, "someNewType"}), + }} + _, err = NewServer(o) + if err == nil || !strings.Contains(err.Error(), "connection type") { + t.Fatalf("Expected error about unknown connection type, got %v", err) + } + o.Nkeys[0].AllowedConnectionTypes = testCreateAllowedConnectionTypes([]string{"websocket"}) + s, err = NewServer(o) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + s.mu.Lock() + nkey := s.opts.Nkeys[0] + s.mu.Unlock() + for act := range nkey.AllowedConnectionTypes { + if act != jwt.ConnectionTypeWebsocket { + t.Fatalf("Expected map to have been updated with proper case, got %v", act) + } + } +}