From a67704e245a07cef9afc2be551761d28bd8a95e3 Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Mon, 26 Apr 2021 20:50:56 -0400 Subject: [PATCH] [fixed] crash when using nats-resolver without system account (#2162) * [fixed] crash when using nats-resolver without system account Fixes #2160 Will raise an error instead Signed-off-by: Matthias Hanel --- server/jwt.go | 11 +++++++++-- server/jwt_test.go | 22 ++++++++++++++++++++++ server/leafnode_test.go | 9 ++++++++- server/server.go | 3 +++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/server/jwt.go b/server/jwt.go index dda182a9..a41f79d7 100644 --- a/server/jwt.go +++ b/server/jwt.go @@ -96,11 +96,11 @@ func validateTrustedOperators(o *Options) error { if len(o.TrustedOperators) > 0 && len(o.TrustedKeys) > 0 { return fmt.Errorf("conflicting options for 'TrustedKeys' and 'TrustedOperators'") } - if o.SystemAccount != "" { + if o.SystemAccount != _EMPTY_ { foundSys := false foundNonEmpty := false for _, op := range o.TrustedOperators { - if op.SystemAccount != "" { + if op.SystemAccount != _EMPTY_ { foundNonEmpty = true } if op.SystemAccount == o.SystemAccount { @@ -111,6 +111,13 @@ func validateTrustedOperators(o *Options) error { if foundNonEmpty && !foundSys { return fmt.Errorf("system_account in config and operator JWT must be identical") } + } else if o.TrustedOperators[0].SystemAccount == _EMPTY_ { + // In case the system account is neither defined in config nor in the first operator. + // If it would be needed due to the nats account resolver, raise an error. + switch o.AccountResolver.(type) { + case *DirAccResolver, *CacheDirAccResolver: + return fmt.Errorf("using nats based account resolver - the system account needs to be specified in configuration or the operator jwt") + } } ver := strings.Split(strings.Split(VERSION, "-")[0], ".RC")[0] srvMajor, srvMinor, srvUpdate, _ := jwt.ParseServerVersion(ver) diff --git a/server/jwt_test.go b/server/jwt_test.go index e1940886..27e7cb61 100644 --- a/server/jwt_test.go +++ b/server/jwt_test.go @@ -5739,3 +5739,25 @@ func TestJWTMappings(t *testing.T) { require_Len(t, 1, updateJwt(t, srv.ClientURL(), sysCreds, aJwtNoM, 1)) test("foo2", "bar2", true) } + +func TestJWTNoSystemAccountButNatsResolver(t *testing.T) { + dirSrv := createDir(t, "srv") + defer removeDir(t, dirSrv) + for _, resType := range []string{"full", "cache"} { + t.Run(resType, func(t *testing.T) { + conf := createConfFile(t, []byte(fmt.Sprintf(` + listen: -1 + operator: %s + resolver: { + type: %s + dir: %s + }`, ojwt, resType, dirSrv))) + defer removeFile(t, conf) + opts := LoadConfig(conf) + s, err := NewServer(opts) + s.Shutdown() + require_Error(t, err) + require_Contains(t, err.Error(), "the system account needs to be specified in configuration or the operator jwt") + }) + } +} diff --git a/server/leafnode_test.go b/server/leafnode_test.go index df989668..d4559226 100644 --- a/server/leafnode_test.go +++ b/server/leafnode_test.go @@ -28,6 +28,8 @@ import ( "testing" "time" + "github.com/nats-io/nkeys" + jwt "github.com/nats-io/jwt/v2" "github.com/nats-io/nats.go" ) @@ -2455,6 +2457,10 @@ func TestLeafNodeRouteParseLSUnsub(t *testing.T) { } func TestLeafNodeOperatorBadCfg(t *testing.T) { + sysAcc, err := nkeys.CreateAccount() + require_NoError(t, err) + sysAccPk, err := sysAcc.PublicKey() + require_NoError(t, err) tmpDir := createDir(t, "_nats-server") defer removeDir(t, tmpDir) for errorText, cfg := range map[string]string{ @@ -2474,6 +2480,7 @@ func TestLeafNodeOperatorBadCfg(t *testing.T) { conf := createConfFile(t, []byte(fmt.Sprintf(` port: -1 operator: %s + system_account: %s resolver: { type: cache dir: %s @@ -2481,7 +2488,7 @@ func TestLeafNodeOperatorBadCfg(t *testing.T) { leafnodes: { %s } - `, ojwt, tmpDir, cfg))) + `, ojwt, sysAccPk, tmpDir, cfg))) defer removeFile(t, conf) opts := LoadConfig(conf) s, err := NewServer(opts) diff --git a/server/server.go b/server/server.go index d6a4ec44..a9612e76 100644 --- a/server/server.go +++ b/server/server.go @@ -1664,6 +1664,9 @@ func (s *Server) Start() { // Shutdown will shutdown the server instance by kicking out the AcceptLoop // and closing all associated clients. func (s *Server) Shutdown() { + if s == nil { + return + } // Transfer off any raft nodes that we are a leader by shutting them all down. s.shutdownRaftNodes()