mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 03:38:42 -07:00
[FIXED/CHANGED] Add leafnode websocket connection type
This was missing since WEBSOCKET allowed connection type is really used for client connections. If one wants to limit a configured user to leafnode connections, including if the connection is over websocket, but does not want an application to connect over websocket using this user, this would have been impossible to configure. The JWT library has been updated to add LEAFNODE_WS and MQTT_WS for future work. Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
This commit is contained in:
2
go.mod
2
go.mod
@@ -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
4
go.sum
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
2
vendor/github.com/nats-io/jwt/v2/header.go
generated
vendored
2
vendor/github.com/nats-io/jwt/v2/header.go
generated
vendored
@@ -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
|
||||
|
||||
16
vendor/github.com/nats-io/jwt/v2/signingkeys.go
generated
vendored
16
vendor/github.com/nats-io/jwt/v2/signingkeys.go
generated
vendored
@@ -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"])
|
||||
}
|
||||
|
||||
10
vendor/github.com/nats-io/jwt/v2/user_claims.go
generated
vendored
10
vendor/github.com/nats-io/jwt/v2/user_claims.go
generated
vendored
@@ -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
2
vendor/modules.txt
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user