mirror of
https://github.com/gogrlx/nats-server.git
synced 2026-04-02 11:48:43 -07:00
Merge pull request #737 from nats-io/route_perm2
Route permission propogation
This commit is contained in:
@@ -253,6 +253,10 @@ type clientOpts struct {
|
||||
Lang string `json:"lang"`
|
||||
Version string `json:"version"`
|
||||
Protocol int `json:"protocol"`
|
||||
|
||||
// Routes only
|
||||
Import *SubjectPermission `json:"import,omitempty"`
|
||||
Export *SubjectPermission `json:"export,omitempty"`
|
||||
}
|
||||
|
||||
var defaultOpts = clientOpts{Verbose: true, Pedantic: true, Echo: true}
|
||||
|
||||
@@ -55,8 +55,8 @@ const (
|
||||
DEFAULT_HOST = "0.0.0.0"
|
||||
|
||||
// MAX_CONTROL_LINE_SIZE is the maximum allowed protocol control line size.
|
||||
// 1k should be plenty since payloads sans connect string are separate
|
||||
MAX_CONTROL_LINE_SIZE = 1024
|
||||
// 4k should be plenty since payloads sans connect/info string are separate.
|
||||
MAX_CONTROL_LINE_SIZE = 4096
|
||||
|
||||
// MAX_PAYLOAD_SIZE is the maximum allowed payload size. Should be using
|
||||
// something different if > 1MB payloads are needed.
|
||||
|
||||
@@ -532,8 +532,8 @@ func (s *Server) HandleConnz(w http.ResponseWriter, r *http.Request) {
|
||||
type Routez struct {
|
||||
ID string `json:"server_id"`
|
||||
Now time.Time `json:"now"`
|
||||
Imports *SubjectPermission `json:"imports,omitempty"`
|
||||
Exports *SubjectPermission `json:"exports,omitempty"`
|
||||
Import *SubjectPermission `json:"import,omitempty"`
|
||||
Export *SubjectPermission `json:"export,omitempty"`
|
||||
NumRoutes int `json:"num_routes"`
|
||||
Routes []*RouteInfo `json:"routes"`
|
||||
}
|
||||
@@ -546,19 +546,21 @@ type RoutezOptions struct {
|
||||
|
||||
// RouteInfo has detailed information on a per connection basis.
|
||||
type RouteInfo struct {
|
||||
Rid uint64 `json:"rid"`
|
||||
RemoteID string `json:"remote_id"`
|
||||
DidSolicit bool `json:"did_solicit"`
|
||||
IsConfigured bool `json:"is_configured"`
|
||||
IP string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
Pending int `json:"pending_size"`
|
||||
InMsgs int64 `json:"in_msgs"`
|
||||
OutMsgs int64 `json:"out_msgs"`
|
||||
InBytes int64 `json:"in_bytes"`
|
||||
OutBytes int64 `json:"out_bytes"`
|
||||
NumSubs uint32 `json:"subscriptions"`
|
||||
Subs []string `json:"subscriptions_list,omitempty"`
|
||||
Rid uint64 `json:"rid"`
|
||||
RemoteID string `json:"remote_id"`
|
||||
DidSolicit bool `json:"did_solicit"`
|
||||
IsConfigured bool `json:"is_configured"`
|
||||
IP string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
Import *SubjectPermission `json:"import,omitempty"`
|
||||
Export *SubjectPermission `json:"export,omitempty"`
|
||||
Pending int `json:"pending_size"`
|
||||
InMsgs int64 `json:"in_msgs"`
|
||||
OutMsgs int64 `json:"out_msgs"`
|
||||
InBytes int64 `json:"in_bytes"`
|
||||
OutBytes int64 `json:"out_bytes"`
|
||||
NumSubs uint32 `json:"subscriptions"`
|
||||
Subs []string `json:"subscriptions_list,omitempty"`
|
||||
}
|
||||
|
||||
// Routez returns a Routez struct containing inormation about routes.
|
||||
@@ -575,10 +577,9 @@ func (s *Server) Routez(routezOpts *RoutezOptions) (*Routez, error) {
|
||||
rs.ID = s.info.ID
|
||||
|
||||
// Check for defined permissions for all connected routes.
|
||||
perms := s.getOpts().Cluster.Permissions
|
||||
if perms != nil {
|
||||
rs.Imports = perms.Import
|
||||
rs.Exports = perms.Export
|
||||
if perms := s.getOpts().Cluster.Permissions; perms != nil {
|
||||
rs.Import = perms.Import
|
||||
rs.Export = perms.Export
|
||||
}
|
||||
|
||||
// Walk the list
|
||||
@@ -594,6 +595,8 @@ func (s *Server) Routez(routezOpts *RoutezOptions) (*Routez, error) {
|
||||
InBytes: atomic.LoadInt64(&r.inBytes),
|
||||
OutBytes: r.outBytes,
|
||||
NumSubs: uint32(len(r.subs)),
|
||||
Import: r.opts.Import,
|
||||
Export: r.opts.Export,
|
||||
}
|
||||
|
||||
if subs && len(r.subs) > 0 {
|
||||
|
||||
@@ -1946,23 +1946,38 @@ func TestRoutezPermissions(t *testing.T) {
|
||||
rz := pollRoutez(t, servers[i], mode, url, nil)
|
||||
// For server 1, we expect to see imports and exports
|
||||
if i == 0 {
|
||||
if rz.Imports == nil || rz.Imports.Allow == nil ||
|
||||
len(rz.Imports.Allow) != 1 || rz.Imports.Allow[0] != "foo" ||
|
||||
rz.Imports.Deny != nil {
|
||||
t.Fatalf("Unexpected Imports %v", rz.Imports)
|
||||
if rz.Import == nil || rz.Import.Allow == nil ||
|
||||
len(rz.Import.Allow) != 1 || rz.Import.Allow[0] != "foo" ||
|
||||
rz.Import.Deny != nil {
|
||||
t.Fatalf("Unexpected Import %v", rz.Import)
|
||||
}
|
||||
if rz.Exports == nil || rz.Exports.Allow == nil || rz.Exports.Deny == nil ||
|
||||
len(rz.Exports.Allow) != 1 || rz.Exports.Allow[0] != "*" ||
|
||||
len(rz.Exports.Deny) != 2 || rz.Exports.Deny[0] != "foo" || rz.Exports.Deny[1] != "nats" {
|
||||
t.Fatalf("Unexpected Exports %v", rz.Exports)
|
||||
if rz.Export == nil || rz.Export.Allow == nil || rz.Export.Deny == nil ||
|
||||
len(rz.Export.Allow) != 1 || rz.Export.Allow[0] != "*" ||
|
||||
len(rz.Export.Deny) != 2 || rz.Export.Deny[0] != "foo" || rz.Export.Deny[1] != "nats" {
|
||||
t.Fatalf("Unexpected Export %v", rz.Export)
|
||||
}
|
||||
} else {
|
||||
// We expect to see NO imports and exports for server B.
|
||||
if rz.Imports != nil {
|
||||
t.Fatal("Routez body should NOT contain \"imports\" information.")
|
||||
// We expect to see NO imports and exports for server B by default.
|
||||
if rz.Import != nil {
|
||||
t.Fatal("Routez body should NOT contain \"import\" information.")
|
||||
}
|
||||
if rz.Exports != nil {
|
||||
t.Fatal("Routez body should NOT contain \"exports\" information.")
|
||||
if rz.Export != nil {
|
||||
t.Fatal("Routez body should NOT contain \"export\" information.")
|
||||
}
|
||||
// We do expect to see them show up for the information we have on Server A though.
|
||||
if len(rz.Routes) != 1 {
|
||||
t.Fatalf("Expected route array of 1, got %v\n", len(rz.Routes))
|
||||
}
|
||||
route := rz.Routes[0]
|
||||
if route.Import == nil || route.Import.Allow == nil ||
|
||||
len(route.Import.Allow) != 1 || route.Import.Allow[0] != "foo" ||
|
||||
route.Import.Deny != nil {
|
||||
t.Fatalf("Unexpected Import %v", route.Import)
|
||||
}
|
||||
if route.Export == nil || route.Export.Allow == nil || route.Export.Deny == nil ||
|
||||
len(route.Export.Allow) != 1 || route.Export.Allow[0] != "*" ||
|
||||
len(route.Export.Deny) != 2 || route.Export.Deny[0] != "foo" || route.Export.Deny[1] != "nats" {
|
||||
t.Fatalf("Unexpected Export %v", route.Export)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ func TestConfigReloadUnsupported(t *testing.T) {
|
||||
Debug: false,
|
||||
Trace: false,
|
||||
Logtime: false,
|
||||
MaxControlLine: 1024,
|
||||
MaxControlLine: 4096,
|
||||
MaxPayload: 1048576,
|
||||
MaxConn: 65536,
|
||||
PingInterval: 2 * time.Minute,
|
||||
@@ -213,7 +213,7 @@ func TestConfigReloadInvalidConfig(t *testing.T) {
|
||||
Debug: false,
|
||||
Trace: false,
|
||||
Logtime: false,
|
||||
MaxControlLine: 1024,
|
||||
MaxControlLine: 4096,
|
||||
MaxPayload: 1048576,
|
||||
MaxConn: 65536,
|
||||
PingInterval: 2 * time.Minute,
|
||||
@@ -284,7 +284,7 @@ func TestConfigReload(t *testing.T) {
|
||||
Trace: false,
|
||||
NoLog: true,
|
||||
Logtime: false,
|
||||
MaxControlLine: 1024,
|
||||
MaxControlLine: 4096,
|
||||
MaxPayload: 1048576,
|
||||
MaxConn: 65536,
|
||||
PingInterval: 2 * time.Minute,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
@@ -268,6 +269,7 @@ func (c *client) sendConnect(tlsRequired bool) {
|
||||
TLS: tlsRequired,
|
||||
Name: c.srv.info.ID,
|
||||
}
|
||||
|
||||
b, err := json.Marshal(cinfo)
|
||||
if err != nil {
|
||||
c.Errorf("Error marshaling CONNECT to route: %v\n", err)
|
||||
@@ -316,6 +318,10 @@ func (c *client) processRouteInfo(info *Info) {
|
||||
c.route.authRequired = info.AuthRequired
|
||||
c.route.tlsRequired = info.TLSRequired
|
||||
|
||||
// Copy over permissions as well.
|
||||
c.opts.Import = info.Import
|
||||
c.opts.Export = info.Export
|
||||
|
||||
// If we do not know this route's URL, construct one on the fly
|
||||
// from the information provided.
|
||||
if c.route.url == nil {
|
||||
@@ -911,6 +917,7 @@ func (s *Server) routeAcceptLoop(ch chan struct{}) {
|
||||
info := Info{
|
||||
ID: s.info.ID,
|
||||
Version: s.info.Version,
|
||||
GoVersion: runtime.Version(),
|
||||
AuthRequired: false,
|
||||
TLSRequired: tlsReq,
|
||||
TLSVerify: tlsReq,
|
||||
@@ -932,6 +939,11 @@ func (s *Server) routeAcceptLoop(ch chan struct{}) {
|
||||
if opts.Cluster.Username != "" {
|
||||
info.AuthRequired = true
|
||||
}
|
||||
// Check for permissions.
|
||||
if opts.Cluster.Permissions != nil {
|
||||
info.Import = opts.Cluster.Permissions.Import
|
||||
info.Export = opts.Cluster.Permissions.Export
|
||||
}
|
||||
s.routeInfo = info
|
||||
// Possibly override Host/Port and set IP based on Cluster.Advertise
|
||||
if err := s.setRouteInfoHostPortAndIP(); err != nil {
|
||||
|
||||
@@ -41,20 +41,24 @@ import (
|
||||
// Info is the information sent to clients to help them understand information
|
||||
// about this server.
|
||||
type Info struct {
|
||||
ID string `json:"server_id"`
|
||||
Version string `json:"version"`
|
||||
Proto int `json:"proto"`
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
GoVersion string `json:"go"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
AuthRequired bool `json:"auth_required,omitempty"`
|
||||
TLSRequired bool `json:"tls_required,omitempty"`
|
||||
TLSVerify bool `json:"tls_verify,omitempty"`
|
||||
MaxPayload int `json:"max_payload"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
CID uint64 `json:"client_id,omitempty"`
|
||||
ClientConnectURLs []string `json:"connect_urls,omitempty"` // Contains URLs a client can connect to.
|
||||
ID string `json:"server_id"`
|
||||
Version string `json:"version"`
|
||||
Proto int `json:"proto"`
|
||||
GitCommit string `json:"git_commit,omitempty"`
|
||||
GoVersion string `json:"go"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
AuthRequired bool `json:"auth_required,omitempty"`
|
||||
TLSRequired bool `json:"tls_required,omitempty"`
|
||||
TLSVerify bool `json:"tls_verify,omitempty"`
|
||||
MaxPayload int `json:"max_payload"`
|
||||
IP string `json:"ip,omitempty"`
|
||||
CID uint64 `json:"client_id,omitempty"`
|
||||
|
||||
// Route Specific
|
||||
ClientConnectURLs []string `json:"connect_urls,omitempty"` // Contains URLs a client can connect to.
|
||||
Import *SubjectPermission `json:"import,omitempty"`
|
||||
Export *SubjectPermission `json:"export,omitempty"`
|
||||
}
|
||||
|
||||
// Server is our main struct.
|
||||
|
||||
Reference in New Issue
Block a user