Skip to content

Commit

Permalink
Merge pull request #1739 from nats-io/leaf-warning
Browse files Browse the repository at this point in the history
[Added] account name checks for leaf nodes in operator mode
  • Loading branch information
kozlovic committed Nov 24, 2020
2 parents 637717a + b0461e3 commit 120b031
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 39 deletions.
50 changes: 50 additions & 0 deletions server/leafnode.go
Expand Up @@ -125,6 +125,56 @@ func validateLeafNode(o *Options) error {
if err := validateLeafNodeAuthOptions(o); err != nil {
return err
}
// In local config mode, check that leafnode configuration refers to accounts that exist.
if len(o.TrustedOperators) == 0 {
accNames := map[string]struct{}{}
for _, a := range o.Accounts {
accNames[a.Name] = struct{}{}
}
// global account is always created
accNames[DEFAULT_GLOBAL_ACCOUNT] = struct{}{}
// in the context of leaf nodes, empty account means global account
accNames[_EMPTY_] = struct{}{}
// system account either exists or, if not disabled, will be created
if o.SystemAccount == _EMPTY_ && !o.NoSystemAccount {
accNames[DEFAULT_SYSTEM_ACCOUNT] = struct{}{}
}
checkAccountExists := func(accName string, cfgType string) error {
if _, ok := accNames[accName]; !ok {
return fmt.Errorf("cannot find local account %q specified in leafnode %s", accName, cfgType)
}
return nil
}
if err := checkAccountExists(o.LeafNode.Account, "authorization"); err != nil {
return err
}
for _, lu := range o.LeafNode.Users {
if lu.Account == nil { // means global account
continue
}
if err := checkAccountExists(lu.Account.Name, "authorization"); err != nil {
return err
}
}
for _, r := range o.LeafNode.Remotes {
if err := checkAccountExists(r.LocalAccount, "remote"); err != nil {
return err
}
}
} else {
if len(o.LeafNode.Users) != 0 {
return fmt.Errorf("operator mode does not allow specifying user in leafnode config")
}
for _, r := range o.LeafNode.Remotes {
if !nkeys.IsValidPublicAccountKey(r.LocalAccount) {
return fmt.Errorf("operator mode requires account nkeys in remotes")
}
}
if o.LeafNode.Port != 0 && o.LeafNode.Account != "" && !nkeys.IsValidPublicAccountKey(o.LeafNode.Account) {
return fmt.Errorf("operator mode and non account nkeys are incompatible")
}
}

if o.LeafNode.Port == 0 {
return nil
}
Expand Down
46 changes: 46 additions & 0 deletions server/leafnode_test.go
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"net"
"net/url"
"os"
Expand Down Expand Up @@ -1943,3 +1944,48 @@ func TestLeafNodeNoDuplicateWithinCluster(t *testing.T) {
}
}
}

func TestLeafNodeOperatorBadCfg(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "_nats-server")
if err != nil {
t.Fatal("Could not create tmp dir")
}
defer os.RemoveAll(tmpDir)
for errorText, cfg := range map[string]string{
"operator mode does not allow specifying user in leafnode config": `
port: -1
authorization {
users = [{user: "u", password: "p"}]}
}`,
`operator mode and non account nkeys are incompatible`: `
port: -1
authorization {
account: notankey
}`,
`operator mode requires account nkeys in remotes`: `remotes: [{url: u}]`,
} {
t.Run(errorText, func(t *testing.T) {
conf := createConfFile(t, []byte(fmt.Sprintf(`
port: -1
operator: %s
resolver: {
type: cache
dir: %s
}
leafnodes: {
%s
}
`, ojwt, tmpDir, cfg)))
defer os.Remove(conf)
opts := LoadConfig(conf)
s, err := NewServer(opts)
if err == nil {
s.Shutdown()
t.Fatal("Expected an error")
}
if err.Error() != errorText {
t.Fatalf("Expected error %s but got %s", errorText, err)
}
})
}
}
39 changes: 0 additions & 39 deletions server/server.go
Expand Up @@ -414,45 +414,6 @@ func NewServer(opts *Options) (*Server, error) {
return nil, err
}

// In local config mode, check that leafnode configuration
// refers to account that exist.
if len(opts.TrustedOperators) == 0 {
checkAccountExists := func(accName string) error {
if accName == _EMPTY_ {
return nil
}
if _, ok := s.accounts.Load(accName); !ok {
if accName == DEFAULT_SYSTEM_ACCOUNT && opts.SystemAccount == _EMPTY_ && !opts.NoSystemAccount {
return nil
}
return fmt.Errorf("cannot find account %q specified in leafnode authorization", accName)
}
return nil
}
if err := checkAccountExists(opts.LeafNode.Account); err != nil {
return nil, err
}
for _, lu := range opts.LeafNode.Users {
if lu.Account == nil {
continue
}
if err := checkAccountExists(lu.Account.Name); err != nil {
return nil, err
}
}
for _, r := range opts.LeafNode.Remotes {
if r.LocalAccount == _EMPTY_ {
continue
}
if _, ok := s.accounts.Load(r.LocalAccount); !ok {
if r.LocalAccount == DEFAULT_SYSTEM_ACCOUNT && opts.SystemAccount == _EMPTY_ && !opts.NoSystemAccount {
continue
}
return nil, fmt.Errorf("no local account %q for remote leafnode", r.LocalAccount)
}
}
}

// Used to setup Authorization.
s.configureAuthorization()

Expand Down

0 comments on commit 120b031

Please sign in to comment.