Skip to content

Commit

Permalink
fix(leafnode): credentials parsing for leafnode connections doesn't h…
Browse files Browse the repository at this point in the history
…andle CRLFs correctly (#6175)

Leaf node credential parsing was using a regular expression that didn't
handle CRLFs correctly

Fix #6167

Signed-off-by: Your Name <[email protected]>

---------

Signed-off-by: Alberto Ricart <[email protected]>
  • Loading branch information
aricart authored Nov 26, 2024
1 parent 4978da5 commit fa50c75
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 1 deletion.
2 changes: 1 addition & 1 deletion server/leafnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ func (s *Server) startLeafNodeAcceptLoop() {
}

// RegEx to match a creds file with user JWT and Seed.
var credsRe = regexp.MustCompile(`\s*(?:(?:[-]{3,}[^\n]*[-]{3,}\n)(.+)(?:\n\s*[-]{3,}[^\n]*[-]{3,}\n))`)
var credsRe = regexp.MustCompile(`\s*(?:(?:[-]{3,}.*[-]{3,}\r?\n)([\w\-.=]+)(?:\r?\n[-]{3,}.*[-]{3,}(\r?\n|\z)))`)

// clusterName is provided as argument to avoid lock ordering issues with the locked client c
// Lock should be held entering here.
Expand Down
97 changes: 97 additions & 0 deletions server/leafnode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"strings"
"sync"
Expand Down Expand Up @@ -9075,3 +9076,99 @@ func TestLeafNodeBannerNoClusterNameIfNoCluster(t *testing.T) {
}
l.Unlock()
}

func TestLeafCredFormatting(t *testing.T) {
//create the operator/sys/account tree
oKP, err := nkeys.CreateOperator()
require_NoError(t, err)
oPK, err := oKP.PublicKey()
require_NoError(t, err)

oc := jwt.NewOperatorClaims(oPK)
oc.Name = "O"
oJWT, err := oc.Encode(oKP)
require_NoError(t, err)

sysKP, err := nkeys.CreateAccount()
require_NoError(t, err)
sysPK, err := sysKP.PublicKey()
require_NoError(t, err)

sys := jwt.NewAccountClaims(sysPK)
sys.Name = "SYS"
sysJWT, err := sys.Encode(oKP)
require_NoError(t, err)

aKP, err := nkeys.CreateAccount()
require_NoError(t, err)
aPK, err := aKP.PublicKey()
require_NoError(t, err)

ac := jwt.NewAccountClaims(aPK)
ac.Name = "A"
aJWT, err := ac.Encode(oKP)
require_NoError(t, err)

uKP, err := nkeys.CreateUser()
require_NoError(t, err)
uSeed, err := uKP.Seed()
require_NoError(t, err)
uPK, err := uKP.PublicKey()
require_NoError(t, err)

// build the config
stmpl := fmt.Sprintf(`
listen: 127.0.0.1:-1
operator: %s
system_account: %s
resolver: MEM
resolver_preload: {
%s: %s
%s: %s
}
leaf { listen: 127.0.0.1:-1 }
`, oJWT, sysPK, sysPK, sysJWT, aPK, aJWT)
conf := createConfFile(t, []byte(stmpl))
s, o := RunServerWithConfig(conf)
defer s.Shutdown()

// create the leaf node
// generate the user credentials
uc := jwt.NewUserClaims(uPK)
uc.Name = "U"
uc.Limits.Data = -1
uc.Limits.Payload = -1
uc.Permissions.Pub.Allow.Add(">")
uc.Permissions.Sub.Allow.Add(">")
uJWT, err := uc.Encode(aKP)
require_NoError(t, err)

runLeaf := func(t *testing.T, creds []byte) {
file, err := os.CreateTemp("", "tmp-*.creds")
require_NoError(t, err)
_, err = file.Write(creds)
require_NoError(t, err)
require_NoError(t, file.Close())

template := fmt.Sprintf(`
listen: 127.0.0.1:-1
leaf { remotes: [
{
urls: [ nats-leaf://127.0.0.1:%d ]
credentials: "%s"
}
] }`, o.LeafNode.Port, file.Name())

conf := createConfFile(t, []byte(template))
leaf, _ := RunServerWithConfig(conf)
defer leaf.Shutdown()
defer os.Remove(file.Name())
checkLeafNodeConnected(t, leaf)
}

creds, err := jwt.FormatUserConfig(uJWT, uSeed)
require_NoError(t, err)

runLeaf(t, creds)
runLeaf(t, bytes.ReplaceAll(creds, []byte{'\n'}, []byte{'\r', '\n'}))
}

0 comments on commit fa50c75

Please sign in to comment.