mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-14 18:20:42 -07:00
[fixed] issue where js overwrote leafnode remotes permissions from creds
Fixes #2415. We did a set instead of merge. changes in `jwt_test.go` are to make the `createUserWithLimit` usable by my new test. Signed-off-by: Matthias Hanel <mh@synadia.com>
This commit is contained in:
@@ -3864,7 +3864,7 @@ func newTimeRange(start time.Time, dur time.Duration) jwt.TimeRange {
|
||||
return jwt.TimeRange{Start: start.Format("15:04:05"), End: start.Add(dur).Format("15:04:05")}
|
||||
}
|
||||
|
||||
func createUserWithLimit(t *testing.T, accKp nkeys.KeyPair, expiration time.Time, limits func(*jwt.Limits)) string {
|
||||
func createUserWithLimit(t *testing.T, accKp nkeys.KeyPair, expiration time.Time, limits func(*jwt.UserPermissionLimits)) string {
|
||||
t.Helper()
|
||||
ukp, _ := nkeys.CreateUser()
|
||||
seed, _ := ukp.Seed()
|
||||
@@ -3872,7 +3872,7 @@ func createUserWithLimit(t *testing.T, accKp nkeys.KeyPair, expiration time.Time
|
||||
uclaim := newJWTTestUserClaims()
|
||||
uclaim.Subject = upub
|
||||
if limits != nil {
|
||||
limits(&uclaim.Limits)
|
||||
limits(&uclaim.UserPermissionLimits)
|
||||
}
|
||||
if !expiration.IsZero() {
|
||||
uclaim.Expires = expiration.Unix()
|
||||
@@ -3909,31 +3909,33 @@ func TestJWTUserLimits(t *testing.T) {
|
||||
defer sA.Shutdown()
|
||||
for _, v := range []struct {
|
||||
pass bool
|
||||
f func(*jwt.Limits)
|
||||
f func(*jwt.UserPermissionLimits)
|
||||
}{
|
||||
{true, nil},
|
||||
{false, func(j *jwt.Limits) { j.Src.Set("8.8.8.8/8") }},
|
||||
{true, func(j *jwt.Limits) { j.Src.Set("8.8.8.8/0") }},
|
||||
{true, func(j *jwt.Limits) { j.Src.Set("127.0.0.1/8") }},
|
||||
{true, func(j *jwt.Limits) { j.Src.Set("8.8.8.8/8,127.0.0.1/8") }},
|
||||
{false, func(j *jwt.Limits) { j.Src.Set("8.8.8.8/8,9.9.9.9/8") }},
|
||||
{true, func(j *jwt.Limits) { j.Times = append(j.Times, newTimeRange(time.Now(), time.Hour)) }},
|
||||
{false, func(j *jwt.Limits) { j.Times = append(j.Times, newTimeRange(time.Now().Add(time.Hour), time.Hour)) }},
|
||||
{true, func(j *jwt.Limits) {
|
||||
{false, func(j *jwt.UserPermissionLimits) { j.Src.Set("8.8.8.8/8") }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Src.Set("8.8.8.8/0") }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Src.Set("127.0.0.1/8") }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Src.Set("8.8.8.8/8,127.0.0.1/8") }},
|
||||
{false, func(j *jwt.UserPermissionLimits) { j.Src.Set("8.8.8.8/8,9.9.9.9/8") }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Times = append(j.Times, newTimeRange(time.Now(), time.Hour)) }},
|
||||
{false, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = append(j.Times, newTimeRange(time.Now().Add(time.Hour), time.Hour))
|
||||
}},
|
||||
{true, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = append(j.Times, newTimeRange(inAnHour, time.Hour), newTimeRange(time.Now(), time.Hour))
|
||||
}}, // last one is within range
|
||||
{false, func(j *jwt.Limits) {
|
||||
{false, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = append(j.Times, newTimeRange(inAnHour, time.Hour), newTimeRange(inTwoHours, time.Hour))
|
||||
}}, // out of range
|
||||
{false, func(j *jwt.Limits) {
|
||||
{false, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = append(j.Times, newTimeRange(inAnHour, 3*time.Hour), newTimeRange(inTwoHours, 2*time.Hour))
|
||||
}}, // overlapping [a[]b] out of range*/
|
||||
{false, func(j *jwt.Limits) {
|
||||
{false, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = append(j.Times, newTimeRange(inAnHour, 3*time.Hour), newTimeRange(inTwoHours, time.Hour))
|
||||
}}, // overlapping [a[b]] out of range
|
||||
// next day tests where end < begin
|
||||
{true, func(j *jwt.Limits) { j.Times = append(j.Times, newTimeRange(time.Now(), 25*time.Hour)) }},
|
||||
{true, func(j *jwt.Limits) { j.Times = append(j.Times, newTimeRange(time.Now(), -time.Hour)) }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Times = append(j.Times, newTimeRange(time.Now(), 25*time.Hour)) }},
|
||||
{true, func(j *jwt.UserPermissionLimits) { j.Times = append(j.Times, newTimeRange(time.Now(), -time.Hour)) }},
|
||||
} {
|
||||
t.Run("", func(t *testing.T) {
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, v.f)
|
||||
@@ -3976,7 +3978,7 @@ func TestJWTTimeExpiration(t *testing.T) {
|
||||
for _, l := range []string{"", "Europe/Berlin", "America/New_York"} {
|
||||
t.Run("simple expiration "+l, func(t *testing.T) {
|
||||
start := time.Now()
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.Limits) {
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.UserPermissionLimits) {
|
||||
if l == "" {
|
||||
j.Times = []jwt.TimeRange{newTimeRange(start, validFor)}
|
||||
} else {
|
||||
@@ -4020,7 +4022,7 @@ func TestJWTTimeExpiration(t *testing.T) {
|
||||
t.Run("double expiration", func(t *testing.T) {
|
||||
start1 := time.Now()
|
||||
start2 := start1.Add(2 * validFor)
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.Limits) {
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.UserPermissionLimits) {
|
||||
j.Times = []jwt.TimeRange{newTimeRange(start1, validFor), newTimeRange(start2, validFor)}
|
||||
})
|
||||
defer removeFile(t, creds)
|
||||
@@ -4059,7 +4061,7 @@ func TestJWTTimeExpiration(t *testing.T) {
|
||||
})
|
||||
t.Run("lower jwt expiration overwrites time", func(t *testing.T) {
|
||||
start := time.Now()
|
||||
creds := createUserWithLimit(t, kp, start.Add(validFor), func(j *jwt.Limits) { j.Times = []jwt.TimeRange{newTimeRange(start, 2*validFor)} })
|
||||
creds := createUserWithLimit(t, kp, start.Add(validFor), func(j *jwt.UserPermissionLimits) { j.Times = []jwt.TimeRange{newTimeRange(start, 2*validFor)} })
|
||||
defer removeFile(t, creds)
|
||||
disconnectChan := make(chan struct{})
|
||||
defer close(disconnectChan)
|
||||
@@ -4114,7 +4116,7 @@ func TestJWTLimits(t *testing.T) {
|
||||
errChan := make(chan struct{})
|
||||
defer close(errChan)
|
||||
t.Run("subs", func(t *testing.T) {
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.Limits) { j.Subs = 1 })
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.UserPermissionLimits) { j.Subs = 1 })
|
||||
defer removeFile(t, creds)
|
||||
c := natsConnect(t, sA.ClientURL(), nats.UserCredentials(creds),
|
||||
nats.DisconnectErrHandler(func(conn *nats.Conn, err error) {
|
||||
@@ -4133,7 +4135,7 @@ func TestJWTLimits(t *testing.T) {
|
||||
chanRecv(t, errChan, time.Second)
|
||||
})
|
||||
t.Run("payload", func(t *testing.T) {
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.Limits) { j.Payload = 5 })
|
||||
creds := createUserWithLimit(t, kp, doNotExpire, func(j *jwt.UserPermissionLimits) { j.Payload = 5 })
|
||||
defer removeFile(t, creds)
|
||||
c := natsConnect(t, sA.ClientURL(), nats.UserCredentials(creds))
|
||||
defer c.Close()
|
||||
|
||||
@@ -1362,8 +1362,7 @@ func (c *client) processLeafNodeConnect(s *Server, arg []byte, lang string) erro
|
||||
|
||||
// If we have JS enabled and the other side does as well we need to add in an import deny clause.
|
||||
if jsConfigured && proto.JetStream {
|
||||
// We should never have existing perms here, if that changes this needs to be reworked.
|
||||
c.setPermissions(&Permissions{Publish: &SubjectPermission{Deny: []string{jsAllAPI}}})
|
||||
c.mergePubDenyPermissions([]string{jsAllAPI})
|
||||
}
|
||||
|
||||
// Set the Ping timer
|
||||
|
||||
@@ -3786,3 +3786,124 @@ func TestLeafNodeUniqueServerNameCrossJSDomain(t *testing.T) {
|
||||
test(sA, sA.ID(), sA, sL)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLeafNodeJwtPermsAndJetStreamDomains(t *testing.T) {
|
||||
createAcc := func(js bool) (string, string, nkeys.KeyPair) {
|
||||
kp, _ := nkeys.CreateAccount()
|
||||
aPub, _ := kp.PublicKey()
|
||||
claim := jwt.NewAccountClaims(aPub)
|
||||
if js {
|
||||
claim.Limits.JetStreamLimits = jwt.JetStreamLimits{
|
||||
MemoryStorage: 1024 * 1024,
|
||||
DiskStorage: 1024 * 1024,
|
||||
Streams: 1, Consumer: 2}
|
||||
}
|
||||
aJwt, err := claim.Encode(oKp)
|
||||
require_NoError(t, err)
|
||||
return aPub, aJwt, kp
|
||||
}
|
||||
sysPub, sysJwt, sysKp := createAcc(false)
|
||||
accPub, accJwt, accKp := createAcc(true)
|
||||
noExpiration := time.Now().Add(time.Hour)
|
||||
// create user for acc to be used in leaf node.
|
||||
lnCreds := createUserWithLimit(t, accKp, noExpiration, func(j *jwt.UserPermissionLimits) {
|
||||
j.Sub.Deny.Add("subdeny")
|
||||
j.Pub.Deny.Add("pubdeny")
|
||||
})
|
||||
defer removeFile(t, lnCreds)
|
||||
unlimitedCreds := createUserWithLimit(t, accKp, noExpiration, nil)
|
||||
defer removeFile(t, unlimitedCreds)
|
||||
|
||||
sysCreds := createUserWithLimit(t, sysKp, noExpiration, nil)
|
||||
defer removeFile(t, sysCreds)
|
||||
|
||||
tmplA := `
|
||||
operator: %s
|
||||
system_account: %s
|
||||
resolver: MEMORY
|
||||
resolver_preload: {
|
||||
%s: %s
|
||||
%s: %s
|
||||
}
|
||||
listen: localhost:-1
|
||||
leafnodes: {
|
||||
listen: localhost:-1
|
||||
}
|
||||
jetstream :{
|
||||
domain: "cluster"
|
||||
store_dir: "%s"
|
||||
max_mem: 100Mb
|
||||
max_file: 100Mb
|
||||
}
|
||||
`
|
||||
|
||||
tmplL := `
|
||||
listen: localhost:-1
|
||||
accounts :{
|
||||
A:{ jetstream: enable, users:[ {user:a1,password:a1}]},
|
||||
SYS:{ users:[ {user:s1,password:s1}]},
|
||||
}
|
||||
system_account = SYS
|
||||
jetstream: {
|
||||
domain: ln1
|
||||
store_dir: %s
|
||||
max_mem: 50Mb
|
||||
max_file: 50Mb
|
||||
}
|
||||
leafnodes:{
|
||||
remotes:[{ url:nats://localhost:%d, account: A, credentials: %s},
|
||||
{ url:nats://localhost:%d, account: SYS, credentials: %s}]
|
||||
}
|
||||
`
|
||||
|
||||
confA := createConfFile(t, []byte(fmt.Sprintf(tmplA, ojwt, sysPub,
|
||||
sysPub, sysJwt, accPub, accJwt,
|
||||
createDir(t, JetStreamStoreDir))))
|
||||
defer removeFile(t, confA)
|
||||
sA, _ := RunServerWithConfig(confA)
|
||||
defer sA.Shutdown()
|
||||
|
||||
confL := createConfFile(t, []byte(fmt.Sprintf(tmplL, createDir(t, JetStreamStoreDir),
|
||||
sA.opts.LeafNode.Port, lnCreds, sA.opts.LeafNode.Port, sysCreds)))
|
||||
defer removeFile(t, confL)
|
||||
sL, _ := RunServerWithConfig(confL)
|
||||
defer sL.Shutdown()
|
||||
|
||||
checkLeafNodeConnectedCount(t, sA, 2)
|
||||
checkLeafNodeConnectedCount(t, sL, 2)
|
||||
|
||||
ncA := natsConnect(t, sA.ClientURL(), nats.UserCredentials(unlimitedCreds))
|
||||
defer ncA.Close()
|
||||
|
||||
ncL := natsConnect(t, fmt.Sprintf("nats://a1:a1@localhost:%d", sL.opts.Port))
|
||||
defer ncL.Close()
|
||||
|
||||
test := func(subject string, cSub, cPub *nats.Conn, pass bool) {
|
||||
sub, err := cSub.SubscribeSync(subject)
|
||||
require_NoError(t, err)
|
||||
require_NoError(t, cSub.Flush())
|
||||
require_NoError(t, cPub.Publish(subject, []byte("hello world")))
|
||||
require_NoError(t, cPub.Flush())
|
||||
m, err := sub.NextMsg(500 * time.Millisecond)
|
||||
if pass {
|
||||
require_NoError(t, err)
|
||||
require_True(t, m.Subject == subject)
|
||||
require_Equal(t, string(m.Data), "hello world")
|
||||
} else {
|
||||
require_True(t, err == nats.ErrTimeout)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("sub-on-ln-pass", func(t *testing.T) {
|
||||
test("sub", ncL, ncA, true)
|
||||
})
|
||||
t.Run("sub-on-ln-fail", func(t *testing.T) {
|
||||
test("subdeny", ncL, ncA, false)
|
||||
})
|
||||
t.Run("pub-on-ln-pass", func(t *testing.T) {
|
||||
test("pub", ncA, ncL, true)
|
||||
})
|
||||
t.Run("pub-on-ln-fail", func(t *testing.T) {
|
||||
test("pubdeny", ncA, ncL, false)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user