Merge pull request #2707 from nats-io/leafnode_ws_allowed_conn

[FIXED/CHANGED] Add leafnode websocket connection type
This commit is contained in:
Ivan Kozlovic
2021-11-22 14:39:26 -07:00
committed by GitHub
9 changed files with 64 additions and 27 deletions

2
go.mod
View File

@@ -6,7 +6,7 @@ require (
github.com/golang/protobuf v1.4.2 // indirect
github.com/klauspost/compress v1.13.4
github.com/minio/highwayhash v1.0.1
github.com/nats-io/jwt/v2 v2.1.0
github.com/nats-io/jwt/v2 v2.2.0
github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483
github.com/nats-io/nkeys v0.3.0
github.com/nats-io/nuid v1.0.1

4
go.sum
View File

@@ -14,8 +14,8 @@ github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEE
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/minio/highwayhash v1.0.1 h1:dZ6IIu8Z14VlC0VpfKofAhCy74wu/Qb5gcn52yWoz/0=
github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/nats-io/jwt/v2 v2.1.0 h1:1UbfD5g1xTdWmSeRV8bh/7u+utTiBsRtWhLl1PixZp4=
github.com/nats-io/jwt/v2 v2.1.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
github.com/nats-io/jwt/v2 v2.2.0 h1:Yg/4WFK6vsqMudRg91eBb7Dh6XeVcDMPHycDE8CfltE=
github.com/nats-io/jwt/v2 v2.2.0/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483 h1:GMx3ZOcMEVM5qnUItQ4eJyQ6ycwmIEB/VC/UxvdevE0=
github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483/go.mod h1:BPko4oXsySz4aSWeFgOHLZs3G4Jq4ZAyE6/zMCxRT6w=
github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=

View File

@@ -1104,7 +1104,9 @@ func validateAllowedConnectionTypes(m map[string]struct{}) error {
for ct := range m {
ctuc := strings.ToUpper(ct)
switch ctuc {
case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket, jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeMqtt:
case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket,
jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeLeafnodeWS,
jwt.ConnectionTypeMqtt:
default:
return fmt.Errorf("unknown connection type %q", ct)
}

View File

@@ -5172,7 +5172,9 @@ func convertAllowedConnectionTypes(cts []string) (map[string]struct{}, error) {
for _, i := range cts {
i = strings.ToUpper(i)
switch i {
case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket, jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeMqtt:
case jwt.ConnectionTypeStandard, jwt.ConnectionTypeWebsocket,
jwt.ConnectionTypeLeafnode, jwt.ConnectionTypeLeafnodeWS,
jwt.ConnectionTypeMqtt:
m[i] = struct{}{}
default:
unknown = append(unknown, i)
@@ -5206,7 +5208,11 @@ func (c *client) connectionTypeAllowed(acts map[string]struct{}) bool {
want = jwt.ConnectionTypeMqtt
}
case LEAF:
want = jwt.ConnectionTypeLeafnode
if c.isWebsocket() {
want = jwt.ConnectionTypeLeafnodeWS
} else {
want = jwt.ConnectionTypeLeafnode
}
}
_, ok := acts[want]
return ok

View File

@@ -22,6 +22,7 @@ import (
"math/rand"
"net"
"net/url"
"os"
"strings"
"sync"
"sync/atomic"
@@ -3032,12 +3033,12 @@ func TestLeafNodeWSFailedConnection(t *testing.T) {
}
func TestLeafNodeWSAuth(t *testing.T) {
conf := createConfFile(t, []byte(fmt.Sprintf(`
template := `
port: -1
authorization {
users [
{user: "user", pass: "puser", connection_types: ["%s"]}
{user: "leaf", pass: "pleaf", connection_types: ["%s"]}
{user: "leaf", pass: "pleaf", connection_types: ["%s"%s]}
]
}
websocket {
@@ -3047,20 +3048,40 @@ func TestLeafNodeWSAuth(t *testing.T) {
leafnodes {
port: -1
}
`, jwt.ConnectionTypeStandard, jwt.ConnectionTypeLeafnode)))
defer removeFile(t, conf)
o, err := ProcessConfigFile(conf)
if err != nil {
t.Fatalf("Error processing config file: %v", err)
}
o.NoLog, o.NoSigs = true, true
s := RunServer(o)
`
s, o, conf := runReloadServerWithContent(t,
[]byte(fmt.Sprintf(template, jwt.ConnectionTypeStandard, jwt.ConnectionTypeLeafnode, "")))
defer os.Remove(conf)
defer s.Shutdown()
l := &captureErrorLogger{errCh: make(chan string, 10)}
s.SetLogger(l, false, false)
lo := testDefaultRemoteLeafNodeWSOptions(t, o, false)
u, _ := url.Parse(fmt.Sprintf("ws://leaf:pleaf@127.0.0.1:%d", o.Websocket.Port))
remote := &RemoteLeafOpts{URLs: []*url.URL{u}}
lo.LeafNode.Remotes = []*RemoteLeafOpts{remote}
lo.LeafNode.ReconnectInterval = 50 * time.Millisecond
ln := RunServer(lo)
defer ln.Shutdown()
var lasterr string
tm := time.NewTimer(2 * time.Second)
for done := false; !done; {
select {
case lasterr = <-l.errCh:
if strings.Contains(lasterr, "authentication") {
done = true
}
case <-tm.C:
t.Fatalf("Expected auth error, got %v", lasterr)
}
}
ws := fmt.Sprintf(`, "%s"`, jwt.ConnectionTypeLeafnodeWS)
reloadUpdateConfig(t, s, conf, fmt.Sprintf(template,
jwt.ConnectionTypeStandard, jwt.ConnectionTypeLeafnode, ws))
checkLeafNodeConnected(t, s)
checkLeafNodeConnected(t, ln)

View File

@@ -23,7 +23,7 @@ import (
const (
// Version is semantic version.
Version = "2.1.0"
Version = "2.2.0"
// TokenTypeJwt is the JWT token type supported JWT tokens
// encoded and decoded by this library

View File

@@ -120,9 +120,12 @@ func (sk SigningKeys) Validate(vr *ValidationResults) {
}
// MarshalJSON serializes the scoped signing keys as an array
func (sk SigningKeys) MarshalJSON() ([]byte, error) {
func (sk *SigningKeys) MarshalJSON() ([]byte, error) {
if sk == nil {
return nil, nil
}
var a []interface{}
for k, v := range sk {
for k, v := range *sk {
if v != nil {
a = append(a, v)
} else {
@@ -132,7 +135,10 @@ func (sk SigningKeys) MarshalJSON() ([]byte, error) {
return json.Marshal(a)
}
func (sk SigningKeys) UnmarshalJSON(data []byte) error {
func (sk *SigningKeys) UnmarshalJSON(data []byte) error {
if *sk == nil {
*sk = make(SigningKeys)
}
// read an array - we can have a string or an map
var a []interface{}
if err := json.Unmarshal(data, &a); err != nil {
@@ -141,7 +147,7 @@ func (sk SigningKeys) UnmarshalJSON(data []byte) error {
for _, i := range a {
switch v := i.(type) {
case string:
sk[v] = nil
(*sk)[v] = nil
case map[string]interface{}:
d, err := json.Marshal(v)
if err != nil {
@@ -153,7 +159,7 @@ func (sk SigningKeys) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(d, &us); err != nil {
return err
}
sk[us.Key] = us
(*sk)[us.Key] = us
default:
return fmt.Errorf("unknown signing key scope %q", v["type"])
}

View File

@@ -23,10 +23,12 @@ import (
)
const (
ConnectionTypeStandard = "STANDARD"
ConnectionTypeWebsocket = "WEBSOCKET"
ConnectionTypeLeafnode = "LEAFNODE"
ConnectionTypeMqtt = "MQTT"
ConnectionTypeStandard = "STANDARD"
ConnectionTypeWebsocket = "WEBSOCKET"
ConnectionTypeLeafnode = "LEAFNODE"
ConnectionTypeLeafnodeWS = "LEAFNODE_WS"
ConnectionTypeMqtt = "MQTT"
ConnectionTypeMqttWS = "MQTT_WS"
)
type UserPermissionLimits struct {

2
vendor/modules.txt vendored
View File

@@ -6,7 +6,7 @@ github.com/klauspost/compress/s2
# github.com/minio/highwayhash v1.0.1
## explicit
github.com/minio/highwayhash
# github.com/nats-io/jwt/v2 v2.1.0
# github.com/nats-io/jwt/v2 v2.2.0
## explicit
github.com/nats-io/jwt/v2
# github.com/nats-io/nats.go v1.13.1-0.20211018182449-f2416a8b1483