From 74642e024eb25bb1658ed9789b6f37f5535b2a2d Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Wed, 18 Nov 2020 23:15:04 -0500 Subject: [PATCH 1/5] [Added] verify_and_implicit_allow to tie subject alt name to url in cfg Only works for gateways and routes. When true the subject alt DNS name must match one url in the corresponding configuration Signed-off-by: Matthias Hanel --- server/auth.go | 85 +++++++++++++++---- server/auth_test.go | 58 +++++++++++++ server/config_check_test.go | 47 +++++++++++ server/opts.go | 83 +++++++++++-------- test/tls_test.go | 161 ++++++++++++++++++++++++++++++++++++ 5 files changed, 385 insertions(+), 49 deletions(-) diff --git a/server/auth.go b/server/auth.go index 601e28a4..ae3ca44a 100644 --- a/server/auth.go +++ b/server/auth.go @@ -20,6 +20,7 @@ import ( "encoding/base64" "fmt" "net" + "net/url" "regexp" "strings" "time" @@ -418,7 +419,7 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) boo } else if hasUsers { // Check if we are tls verify and are mapping users from the client_certificate. if tlsMap { - authorized := checkClientTLSCertSubject(c, func(u string, certRDN *ldap.DN) (string, bool) { + authorized := checkClientTLSCertSubject(c, func(u string, certRDN *ldap.DN, _ bool) (string, bool) { // First do literal lookup using the resulting string representation // of RDNSequence as implemented by the pkix package from Go. if u != "" { @@ -667,7 +668,7 @@ func getTLSAuthDCs(rdns *pkix.RDNSequence) string { return strings.Join(dcs, ",") } -type tlsMapAuthFn func(string, *ldap.DN) (string, bool) +type tlsMapAuthFn func(string, *ldap.DN, bool) (string, bool) func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { tlsState := c.GetTLSConnectionState() @@ -696,7 +697,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { switch { case hasEmailAddresses: for _, u := range cert.EmailAddresses { - if match, ok := fn(u, nil); ok { + if match, ok := fn(u, nil, false); ok { c.Debugf("Using email found in cert for auth [%q]", match) return true } @@ -704,7 +705,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { fallthrough case hasSANs: for _, u := range cert.DNSNames { - if match, ok := fn(u, nil); ok { + if match, ok := fn(u, nil, true); ok { c.Debugf("Using SAN found in cert for auth [%q]", match) return true } @@ -712,7 +713,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { fallthrough case hasURIs: for _, u := range cert.URIs { - if match, ok := fn(u.String(), nil); ok { + if match, ok := fn(u.String(), nil, false); ok { c.Debugf("Using URI found in cert for auth [%q]", match) return true } @@ -726,7 +727,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { // Match that follows original order from the subject takes precedence. dn, err := ldap.FromCertSubject(cert.Subject) if err == nil { - if match, ok := fn("", dn); ok { + if match, ok := fn("", dn, false); ok { c.Debugf("Using DistinguishedNameMatch for auth [%q]", match) return true } @@ -745,7 +746,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { dcs := getTLSAuthDCs(&rdns) if len(dcs) > 0 { u := strings.Join([]string{rdn, dcs}, ",") - if match, ok := fn(u, nil); ok { + if match, ok := fn(u, nil, false); ok { c.Debugf("Using RDNSequence for auth [%q]", match) return true } @@ -755,7 +756,7 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { // If no match, then use the string representation of the RDNSequence // from the subject without the domainComponents. - if match, ok := fn(rdn, nil); ok { + if match, ok := fn(rdn, nil, false); ok { c.Debugf("Using certificate subject for auth [%q]", match) return true } @@ -764,6 +765,38 @@ func checkClientTLSCertSubject(c *client, fn tlsMapAuthFn) bool { return false } +func dnsAltNameLabels(dnsAltName string) []string { + return strings.Split(strings.ToLower(dnsAltName), ".") +} + +// Check DNS name according to https://tools.ietf.org/html/rfc6125#section-6.4.1 +func dnsAltNameMatches(dnsAltNameLabels []string, urls []*url.URL) bool { +URLS: + for _, url := range urls { + if url == nil { + continue URLS + } + hostLabels := strings.Split(strings.ToLower(url.Hostname()), ".") + // following https://tools.ietf.org/html/rfc6125#section-6.4.3, should not => will not, may => will not + // wilcard does not match multiple labels + if len(hostLabels) != len(dnsAltNameLabels) { + continue URLS + } + i := 0 + // only match wildcard on left most label + if dnsAltNameLabels[0] == "*" { + i++ + } + for ; i < len(dnsAltNameLabels); i++ { + if dnsAltNameLabels[i] != hostLabels[i] { + continue URLS + } + } + return true + } + return false +} + // checkRouterAuth checks optional router authorization which can be nil or username/password. func (s *Server) isRouterAuthorized(c *client) bool { // Snapshot server options. @@ -779,9 +812,17 @@ func (s *Server) isRouterAuthorized(c *client) bool { return true } - if opts.Cluster.TLSMap { - return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN) (string, bool) { - return "", opts.Cluster.Username == user + if opts.Cluster.TLSMap || opts.Cluster.TLSImplicitAllow { + return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { + if opts.Cluster.TLSImplicitAllow && isDNSAltName { + if dnsAltNameMatches(dnsAltNameLabels(user), opts.Routes) { + return "", true + } + } + if opts.Cluster.TLSMap && opts.Cluster.Username == user { + return "", true + } + return "", false }) } @@ -803,9 +844,23 @@ func (s *Server) isGatewayAuthorized(c *client) bool { } // Check whether TLS map is enabled, otherwise use single user/pass. - if opts.Gateway.TLSMap { - return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN) (string, bool) { - return "", opts.Gateway.Username == user + if opts.Gateway.TLSMap || opts.Gateway.TLSImplicitAllow { + return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { + if user == "" { + return "", false + } + if opts.Gateway.TLSImplicitAllow && isDNSAltName { + labels := dnsAltNameLabels(user) + for _, gw := range opts.Gateway.Gateways { + if gw != nil && dnsAltNameMatches(labels, gw.URLs) { + return "", true + } + } + } + if opts.Gateway.TLSMap && opts.Gateway.Username == user { + return "", true + } + return "", false }) } @@ -854,7 +909,7 @@ func (s *Server) isLeafNodeAuthorized(c *client) bool { } else if len(opts.LeafNode.Users) > 0 { if opts.LeafNode.TLSMap { var user *User - found := checkClientTLSCertSubject(c, func(u string, _ *ldap.DN) (string, bool) { + found := checkClientTLSCertSubject(c, func(u string, _ *ldap.DN, _ bool) (string, bool) { // This is expected to be a very small array. for _, usr := range opts.LeafNode.Users { if u == usr.Username { diff --git a/server/auth_test.go b/server/auth_test.go index 031c70ec..1fb3acef 100644 --- a/server/auth_test.go +++ b/server/auth_test.go @@ -14,6 +14,7 @@ package server import ( + "net/url" "reflect" "strings" "testing" @@ -154,3 +155,60 @@ func TestUserUnknownAllowedConnectionType(t *testing.T) { } } } + +func TestDNSAltNameMatching(t *testing.T) { + for idx, test := range []struct { + altName string + urls []string + match bool + }{ + {"foo", []string{"FOO"}, true}, + {"foo", []string{".."}, false}, + {"foo", []string{"."}, false}, + {"Foo", []string{"foO"}, true}, + {"FOO", []string{"foo"}, true}, + {"foo1", []string{"bar"}, false}, + {"multi", []string{"m", "mu", "mul", "multi"}, true}, + {"multi", []string{"multi", "m", "mu", "mul"}, true}, + {"foo.bar", []string{"foo", "foo.bar.bar", "foo.baz"}, false}, + {"foo.Bar", []string{"foo", "bar.foo", "Foo.Bar"}, true}, + {"foo.*", []string{"foo", "bar.foo", "Foo.Bar"}, false}, // only match left most + {"f*.bar", []string{"foo", "bar.foo", "Foo.Bar"}, false}, + {"*.bar", []string{"foo.bar"}, true}, + {"*", []string{"baz.bar", "bar", "z.y"}, true}, + {"*", []string{"bar"}, true}, + {"*", []string{"."}, false}, + {"*", []string{""}, true}, + {"*", []string{"*"}, true}, + {"bar.*", []string{"bar.*"}, true}, + {"*.Y-X-red-mgmt.default.svc", []string{"A.Y-X-red-mgmt.default.svc"}, true}, + {"*.Y-X-green-mgmt.default.svc", []string{"A.Y-X-green-mgmt.default.svc"}, true}, + {"*.Y-X-blue-mgmt.default.svc", []string{"A.Y-X-blue-mgmt.default.svc"}, true}, + {"Y-X-red-mgmt", []string{"Y-X-red-mgmt"}, true}, + {"Y-X-red-mgmt", []string{"X-X-red-mgmt"}, false}, + {"Y-X-red-mgmt", []string{"Y-X-green-mgmt"}, false}, + {"Y-X-red-mgmt", []string{"Y"}, false}, + {"Y-X-red-mgmt", []string{"Y-X"}, false}, + {"Y-X-red-mgmt", []string{"Y-X-red"}, false}, + {"Y-X-red-mgmt", []string{"X-red-mgmt"}, false}, + {"Y-X-green-mgmt", []string{"Y-X-green-mgmt"}, true}, + {"Y-X-blue-mgmt", []string{"Y-X-blue-mgmt"}, true}, + {"connect.Y.local", []string{"connect.Y.local"}, true}, + {"connect.Y.local", []string{".Y.local"}, false}, + {"connect.Y.local", []string{"..local"}, false}, + {"gcp.Y.local", []string{"gcp.Y.local"}, true}, + {"uswest1.gcp.Y.local", []string{"uswest1.gcp.Y.local"}, true}, + } { + urlSet := make([]*url.URL, len(test.urls)) + for i, u := range test.urls { + var err error + urlSet[i], err = url.Parse("nats://" + u) + if err != nil { + t.Fatal(err) + } + } + if dnsAltNameMatches(dnsAltNameLabels(test.altName), urlSet) != test.match { + t.Fatal("Test", idx, "Match miss match, expected:", test.match) + } + } +} diff --git a/server/config_check_test.go b/server/config_check_test.go index c6e9ce30..ec82c688 100644 --- a/server/config_check_test.go +++ b/server/config_check_test.go @@ -360,6 +360,19 @@ func TestConfigCheck(t *testing.T) { errorLine: 4, errorPos: 5, }, + { + name: "verify_and_implicit_allow not support for clients", + config: ` + tls = { + cert_file: "configs/certs/server.pem" + key_file: "configs/certs/key.pem" + verify_and_implicit_allow: true + } + `, + err: errors.New("verify_and_implicit_allow not supported in this context"), + errorLine: 5, + errorPos: 10, + }, { name: "when unknown option is in cluster config with defined routes", config: ` @@ -1140,6 +1153,25 @@ func TestConfigCheck(t *testing.T) { errorLine: 0, errorPos: 0, }, + { + name: "verify_and_implicit_allow do not work for leaf nodes", + config: ` + leafnodes { + remotes = [ + { + url: "tls://nats:7422" + tls { + timeout: 0.01 + verify_and_implicit_allow: true + } + } + ] + }`, + //Unexpected error after processing config: /var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/057996446:8:5: + err: errors.New("verify_and_implicit_allow not supported in this context"), + errorLine: 8, + errorPos: 5, + }, { name: "when leafnode remotes use wrong type", config: ` @@ -1360,6 +1392,21 @@ func TestConfigCheck(t *testing.T) { errorLine: 3, errorPos: 21, }, + { + name: "verify_and_implicit_allow not support for websockets", + config: ` + websocket { + tls { + cert_file: "configs/certs/server.pem" + key_file: "configs/certs/key.pem" + verify_and_implicit_allow: true + } + } + `, + err: fmt.Errorf("verify_and_implicit_allow not supported in this context"), + errorLine: 6, + errorPos: 10, + }, } checkConfig := func(config string) error { diff --git a/server/opts.go b/server/opts.go index 817f198d..ed3286dd 100644 --- a/server/opts.go +++ b/server/opts.go @@ -57,20 +57,21 @@ func NoErrOnUnknownFields(noError bool) { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type ClusterOpts struct { - Name string `json:"-"` - Host string `json:"addr,omitempty"` - Port int `json:"cluster_port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - Permissions *RoutePermissions `json:"-"` - TLSTimeout float64 `json:"-"` - TLSConfig *tls.Config `json:"-"` - TLSMap bool `json:"-"` - ListenStr string `json:"-"` - Advertise string `json:"-"` - NoAdvertise bool `json:"-"` - ConnectRetries int `json:"-"` + Name string `json:"-"` + Host string `json:"addr,omitempty"` + Port int `json:"cluster_port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + Permissions *RoutePermissions `json:"-"` + TLSTimeout float64 `json:"-"` + TLSConfig *tls.Config `json:"-"` + TLSMap bool `json:"-"` + TLSImplicitAllow bool `json:"-"` + ListenStr string `json:"-"` + Advertise string `json:"-"` + NoAdvertise bool `json:"-"` + ConnectRetries int `json:"-"` // Not exported (used in tests) resolver netResolver @@ -80,19 +81,20 @@ type ClusterOpts struct { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type GatewayOpts struct { - Name string `json:"name"` - Host string `json:"addr,omitempty"` - Port int `json:"port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - TLSConfig *tls.Config `json:"-"` - TLSTimeout float64 `json:"tls_timeout,omitempty"` - TLSMap bool `json:"-"` - Advertise string `json:"advertise,omitempty"` - ConnectRetries int `json:"connect_retries,omitempty"` - Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` - RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster + Name string `json:"name"` + Host string `json:"addr,omitempty"` + Port int `json:"port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + TLSConfig *tls.Config `json:"-"` + TLSTimeout float64 `json:"tls_timeout,omitempty"` + TLSMap bool `json:"-"` + TLSImplicitAllow bool `json:"-"` + Advertise string `json:"advertise,omitempty"` + ConnectRetries int `json:"connect_retries,omitempty"` + Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` + RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster // Not exported, for tests. resolver netResolver @@ -397,6 +399,7 @@ type TLSConfigOpts struct { Verify bool Insecure bool Map bool + ImplicitAllow bool Timeout float64 Ciphers []uint16 CurvePreferences []tls.CurveID @@ -745,7 +748,7 @@ func (o *Options) processConfigFileLine(k string, v interface{}, errors *[]error case "ping_max": o.MaxPingsOut = int(v.(int64)) case "tls": - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, true) if err != nil { *errors = append(*errors, err) return @@ -924,7 +927,7 @@ func (o *Options) processConfigFileLine(k string, v interface{}, errors *[]error *errors = append(*errors, err) } case "resolver_tls": - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, true) if err != nil { *errors = append(*errors, err) return @@ -1160,6 +1163,7 @@ func parseCluster(v interface{}, opts *Options, errors *[]error, warnings *[]err opts.Cluster.TLSConfig = config opts.Cluster.TLSTimeout = tlsopts.Timeout opts.Cluster.TLSMap = tlsopts.Map + opts.Cluster.TLSImplicitAllow = tlsopts.ImplicitAllow case "cluster_advertise", "advertise": opts.Cluster.Advertise = mv.(string) case "no_advertise": @@ -1275,6 +1279,7 @@ func parseGateway(v interface{}, o *Options, errors *[]error, warnings *[]error) o.Gateway.TLSConfig = config o.Gateway.TLSTimeout = tlsopts.Timeout o.Gateway.TLSMap = tlsopts.Map + o.Gateway.TLSImplicitAllow = tlsopts.ImplicitAllow case "advertise": o.Gateway.Advertise = mv.(string) case "connect_retries": @@ -1481,7 +1486,7 @@ func parseLeafNodes(v interface{}, opts *Options, errors *[]error, warnings *[]e case "reconnect", "reconnect_delay", "reconnect_interval": opts.LeafNode.ReconnectInterval = time.Duration(int(mv.(int64))) * time.Second case "tls": - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, true) if err != nil { *errors = append(*errors, err) continue @@ -1678,7 +1683,7 @@ func parseRemoteLeafNodes(v interface{}, errors *[]error, warnings *[]error) ([] } remote.Credentials = p case "tls": - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, true) if err != nil { *errors = append(*errors, err) continue @@ -1733,7 +1738,7 @@ func parseRemoteLeafNodes(v interface{}, errors *[]error, warnings *[]error) ([] // Parse TLS and returns a TLSConfig and TLSTimeout. // Used by cluster and gateway parsing. func getTLSConfig(tk token) (*tls.Config, *TLSConfigOpts, error) { - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, false) if err != nil { return nil, nil, err } @@ -3203,7 +3208,7 @@ func parseCurvePreferences(curveName string) (tls.CurveID, error) { } // Helper function to parse TLS configs. -func parseTLS(v interface{}) (t *TLSConfigOpts, retErr error) { +func parseTLS(v interface{}, isClientCtx bool) (t *TLSConfigOpts, retErr error) { var ( tlsm map[string]interface{} tc = TLSConfigOpts{} @@ -3253,6 +3258,16 @@ func parseTLS(v interface{}) (t *TLSConfigOpts, retErr error) { } tc.Verify = verify tc.Map = verify + case "verify_and_implicit_allow": + verify, ok := mv.(bool) + if !ok { + return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_map' to be a boolean"} + } + if verify && isClientCtx { + return nil, &configErr{tk, "verify_and_implicit_allow not supported in this context"} + } + tc.Verify = verify + tc.ImplicitAllow = verify case "cipher_suites": ra := mv.([]interface{}) if len(ra) == 0 { @@ -3408,7 +3423,7 @@ func parseWebsocket(v interface{}, o *Options, errors *[]error, warnings *[]erro case "no_tls": o.Websocket.NoTLS = mv.(bool) case "tls": - tc, err := parseTLS(tk) + tc, err := parseTLS(tk, true) if err != nil { *errors = append(*errors, err) continue diff --git a/test/tls_test.go b/test/tls_test.go index 633d88f5..ea4ec256 100644 --- a/test/tls_test.go +++ b/test/tls_test.go @@ -786,6 +786,167 @@ func TestTLSGatewaysCertificateCNBasedAuth(t *testing.T) { } } +func TestTLSRoutesCertificateImplicitAllowPass(t *testing.T) { + testTLSRoutesCertificateImplicitAllow(t, true) +} + +func TestTLSRoutesCertificateImplicitAllowFail(t *testing.T) { + testTLSRoutesCertificateImplicitAllow(t, false) +} + +func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { + // Base config for the servers + cfg, err := ioutil.TempFile("", "cfg") + if err != nil { + t.Fatal(err) + } + if err = cfg.Sync(); err != nil { + t.Fatal(err) + } + cfg.WriteString(` + cluster { + tls { + cert_file = "./configs/certs/tlsauth/server.pem" + key_file = "./configs/certs/tlsauth/server-key.pem" + ca_file = "./configs/certs/tlsauth/ca.pem" + verify_and_implicit_allow = true + timeout = 1 + } + } + `) + + optsA := LoadConfig(cfg.Name()) + optsB := LoadConfig(cfg.Name()) + + routeURLs := "nats://localhost:9935, nats://localhost:9936" + if !pass { + routeURLs = "nats://127.0.0.1:9935, nats://127.0.0.1:9936" + } + optsA.Host = "127.0.0.1" + optsA.Port = 9335 + optsA.Cluster.Name = "xyz" + optsA.Cluster.Host = optsA.Host + optsA.Cluster.Port = 9935 + optsA.Routes = server.RoutesFromStr(routeURLs) + optsA.NoSystemAccount = true + srvA := RunServer(optsA) + defer srvA.Shutdown() + + optsB.Host = "127.0.0.1" + optsB.Port = 9336 + optsB.Cluster.Name = "xyz" + optsB.Cluster.Host = optsB.Host + optsB.Cluster.Port = 9936 + optsB.Routes = server.RoutesFromStr(routeURLs) + optsB.NoSystemAccount = true + srvB := RunServer(optsB) + defer srvB.Shutdown() + + // srvC is not connected to srvA and srvB due to wrong cert + if pass { + checkNumRoutes(t, srvA, 1) + checkNumRoutes(t, srvB, 1) + } else { + time.Sleep(1 * time.Second) + checkNumRoutes(t, srvA, 0) + checkNumRoutes(t, srvB, 0) + } +} + +func TestTLSGatewaysCertificateImplicitAllowPass(t *testing.T) { + testTLSGatewaysCertificateImplicitAllow(t, true) +} + +func TestTLSGatewaysCertificateImplicitAllowFail(t *testing.T) { + testTLSGatewaysCertificateImplicitAllow(t, false) +} + +func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { + // Base config for the servers + cfg, err := ioutil.TempFile("", "cfg") + if err != nil { + t.Fatal(err) + } + if err = cfg.Sync(); err != nil { + t.Fatal(err) + } + cfg.WriteString(` + gateway { + tls { + cert_file = "./configs/certs/tlsauth/server.pem" + key_file = "./configs/certs/tlsauth/server-key.pem" + ca_file = "./configs/certs/tlsauth/ca.pem" + verify_and_implicit_allow = true + timeout = 1 + } + } + `) + + optsA := LoadConfig(cfg.Name()) + optsB := LoadConfig(cfg.Name()) + + urlA := "nats://localhost:9995" + urlB := "nats://localhost:9996" + if !pass { + urlA = "nats://127.0.0.1:9995" + urlB = "nats://127.0.0.1:9996" + } + + gwA, err := url.Parse(urlA) + if err != nil { + t.Fatal(err) + } + gwB, err := url.Parse(urlB) + if err != nil { + t.Fatal(err) + } + + optsA.Host = "127.0.0.1" + optsA.Port = -1 + optsA.Gateway.Name = "A" + optsA.Gateway.Port = 9995 + + optsB.Host = "127.0.0.1" + optsB.Port = -1 + optsB.Gateway.Name = "B" + optsB.Gateway.Port = 9996 + + gateways := make([]*server.RemoteGatewayOpts, 2) + gateways[0] = &server.RemoteGatewayOpts{ + Name: optsA.Gateway.Name, + URLs: []*url.URL{gwA}, + } + gateways[1] = &server.RemoteGatewayOpts{ + Name: optsB.Gateway.Name, + URLs: []*url.URL{gwB}, + } + + optsA.Gateway.Gateways = gateways + optsB.Gateway.Gateways = gateways + + server.SetGatewaysSolicitDelay(100 * time.Millisecond) + defer server.ResetGatewaysSolicitDelay() + + srvA := RunServer(optsA) + defer srvA.Shutdown() + + srvB := RunServer(optsB) + defer srvB.Shutdown() + + // Because we need to use "localhost" in the gw URLs (to match + // hostname in the user/CN), the server may try to connect to + // a [::1], etc.. that may or may not work, so give a lot of + // time for that to complete ok. + if pass { + waitForOutboundGateways(t, srvA, 1, 5*time.Second) + waitForOutboundGateways(t, srvB, 1, 5*time.Second) + } else { + time.Sleep(1 * time.Second) + waitForOutboundGateways(t, srvA, 0, 5*time.Second) + waitForOutboundGateways(t, srvB, 0, 5*time.Second) + } +} + func TestTLSVerifyClientCertificate(t *testing.T) { srv, opts := RunServerWithConfig("./configs/tlsverify_noca.conf") defer srv.Shutdown() From f24aec4af77326374c5d4602764a89e4c93620f7 Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Thu, 19 Nov 2020 14:01:24 -0500 Subject: [PATCH 2/5] Incorporating comments and fixed an issue where code was not invoked had to change failing tests to use insecure as to not fail due to the outgoing connection being not trusted. Signed-off-by: Matthias Hanel --- server/auth.go | 18 +++++++++++------- server/opts.go | 2 +- test/tls_test.go | 34 ++++++++++++++++++++-------------- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/server/auth.go b/server/auth.go index ae3ca44a..f943a09b 100644 --- a/server/auth.go +++ b/server/auth.go @@ -808,12 +808,11 @@ func (s *Server) isRouterAuthorized(c *client) bool { return s.opts.CustomRouterAuthentication.Check(c) } - if opts.Cluster.Username == "" { - return true - } - if opts.Cluster.TLSMap || opts.Cluster.TLSImplicitAllow { return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { + if user == "" { + return "", false + } if opts.Cluster.TLSImplicitAllow && isDNSAltName { if dnsAltNameMatches(dnsAltNameLabels(user), opts.Routes) { return "", true @@ -826,6 +825,10 @@ func (s *Server) isRouterAuthorized(c *client) bool { }) } + if opts.Cluster.Username == "" { + return true + } + if opts.Cluster.Username != c.opts.Username { return false } @@ -839,9 +842,6 @@ func (s *Server) isRouterAuthorized(c *client) bool { func (s *Server) isGatewayAuthorized(c *client) bool { // Snapshot server options. opts := s.getOpts() - if opts.Gateway.Username == "" { - return true - } // Check whether TLS map is enabled, otherwise use single user/pass. if opts.Gateway.TLSMap || opts.Gateway.TLSImplicitAllow { @@ -864,6 +864,10 @@ func (s *Server) isGatewayAuthorized(c *client) bool { }) } + if opts.Gateway.Username == "" { + return true + } + if opts.Gateway.Username != c.opts.Username { return false } diff --git a/server/opts.go b/server/opts.go index ed3286dd..11519832 100644 --- a/server/opts.go +++ b/server/opts.go @@ -3261,7 +3261,7 @@ func parseTLS(v interface{}, isClientCtx bool) (t *TLSConfigOpts, retErr error) case "verify_and_implicit_allow": verify, ok := mv.(bool) if !ok { - return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_map' to be a boolean"} + return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_implicit_allow' to be a boolean"} } if verify && isClientCtx { return nil, &configErr{tk, "verify_and_implicit_allow not supported in this context"} diff --git a/test/tls_test.go b/test/tls_test.go index ea4ec256..71bcc6a6 100644 --- a/test/tls_test.go +++ b/test/tls_test.go @@ -795,25 +795,28 @@ func TestTLSRoutesCertificateImplicitAllowFail(t *testing.T) { } func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { + t.Helper() // Base config for the servers cfg, err := ioutil.TempFile("", "cfg") if err != nil { t.Fatal(err) } - if err = cfg.Sync(); err != nil { - t.Fatal(err) - } - cfg.WriteString(` + defer os.Remove(cfg.Name()) + cfg.WriteString(fmt.Sprintf(` cluster { tls { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" verify_and_implicit_allow = true + insecure = %t timeout = 1 } } - `) + `, !pass)) // set insecure to skip verification on the outgoing end + if err = cfg.Sync(); err != nil { + t.Fatal(err) + } optsA := LoadConfig(cfg.Name()) optsB := LoadConfig(cfg.Name()) @@ -847,7 +850,7 @@ func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { checkNumRoutes(t, srvA, 1) checkNumRoutes(t, srvB, 1) } else { - time.Sleep(1 * time.Second) + time.Sleep(5 * time.Second) checkNumRoutes(t, srvA, 0) checkNumRoutes(t, srvB, 0) } @@ -862,25 +865,28 @@ func TestTLSGatewaysCertificateImplicitAllowFail(t *testing.T) { } func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { + t.Helper() // Base config for the servers cfg, err := ioutil.TempFile("", "cfg") if err != nil { t.Fatal(err) } - if err = cfg.Sync(); err != nil { - t.Fatal(err) - } - cfg.WriteString(` + defer os.Remove(cfg.Name()) + cfg.WriteString(fmt.Sprintf(` gateway { tls { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" verify_and_implicit_allow = true + insecure = %t timeout = 1 } } - `) + `, !pass)) // set insecure to skip verification on the outgoing end + if err = cfg.Sync(); err != nil { + t.Fatal(err) + } optsA := LoadConfig(cfg.Name()) optsB := LoadConfig(cfg.Name()) @@ -941,9 +947,9 @@ func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { waitForOutboundGateways(t, srvA, 1, 5*time.Second) waitForOutboundGateways(t, srvB, 1, 5*time.Second) } else { - time.Sleep(1 * time.Second) - waitForOutboundGateways(t, srvA, 0, 5*time.Second) - waitForOutboundGateways(t, srvB, 0, 5*time.Second) + time.Sleep(5 * time.Second) + waitForOutboundGateways(t, srvA, 0, 1*time.Second) + waitForOutboundGateways(t, srvB, 0, 1*time.Second) } } From 06e4e93185fbf0ec06fdb7590577fc35d20dccbc Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Thu, 19 Nov 2020 16:58:53 -0500 Subject: [PATCH 3/5] Speeding up unit test fail case Signed-off-by: Matthias Hanel --- test/tls_test.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/tls_test.go b/test/tls_test.go index 71bcc6a6..06933110 100644 --- a/test/tls_test.go +++ b/test/tls_test.go @@ -850,9 +850,10 @@ func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { checkNumRoutes(t, srvA, 1) checkNumRoutes(t, srvB, 1) } else { - time.Sleep(5 * time.Second) - checkNumRoutes(t, srvA, 0) - checkNumRoutes(t, srvB, 0) + time.Sleep(1 * time.Second) // the fail case uses the IP, so a short wait is sufficient + if srvA.NumRoutes() != 0 || srvB.NumRoutes() != 0 { + t.Fatal("No route connection expected") + } } } @@ -947,9 +948,10 @@ func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { waitForOutboundGateways(t, srvA, 1, 5*time.Second) waitForOutboundGateways(t, srvB, 1, 5*time.Second) } else { - time.Sleep(5 * time.Second) - waitForOutboundGateways(t, srvA, 0, 1*time.Second) - waitForOutboundGateways(t, srvB, 0, 1*time.Second) + time.Sleep(1 * time.Second) // the fail case uses the IP, so a short wait is sufficient + if srvA.NumOutboundGateways() != 0 || srvB.NumOutboundGateways() != 0 { + t.Fatal("No outbound gateway connection expected") + } } } From eda80ff7b5cf7baa4f171372c0faafd45372f24e Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Fri, 20 Nov 2020 14:27:24 -0500 Subject: [PATCH 4/5] changing the option name verify_and_implicit_allow to verify_and_accept_known_urls This follows the suggestion by phil. I added the and to be similar to verify_and_map. I fixed a minor issue where the implicit verify could be overwriting an explicitly configured one. Signed-off-by: Matthias Hanel --- server/auth.go | 12 +++--- server/config_check_test.go | 18 ++++----- server/opts.go | 80 +++++++++++++++++++------------------ test/tls_test.go | 4 +- 4 files changed, 59 insertions(+), 55 deletions(-) diff --git a/server/auth.go b/server/auth.go index f943a09b..9b6dee97 100644 --- a/server/auth.go +++ b/server/auth.go @@ -777,8 +777,8 @@ URLS: continue URLS } hostLabels := strings.Split(strings.ToLower(url.Hostname()), ".") - // following https://tools.ietf.org/html/rfc6125#section-6.4.3, should not => will not, may => will not - // wilcard does not match multiple labels + // Following https://tools.ietf.org/html/rfc6125#section-6.4.3, should not => will not, may => will not + // The wilcard * never matches multiple label and only matches the left most label. if len(hostLabels) != len(dnsAltNameLabels) { continue URLS } @@ -808,12 +808,12 @@ func (s *Server) isRouterAuthorized(c *client) bool { return s.opts.CustomRouterAuthentication.Check(c) } - if opts.Cluster.TLSMap || opts.Cluster.TLSImplicitAllow { + if opts.Cluster.TLSMap || opts.Cluster.TLSAcceptKnownUrls { return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { if user == "" { return "", false } - if opts.Cluster.TLSImplicitAllow && isDNSAltName { + if opts.Cluster.TLSAcceptKnownUrls && isDNSAltName { if dnsAltNameMatches(dnsAltNameLabels(user), opts.Routes) { return "", true } @@ -844,12 +844,12 @@ func (s *Server) isGatewayAuthorized(c *client) bool { opts := s.getOpts() // Check whether TLS map is enabled, otherwise use single user/pass. - if opts.Gateway.TLSMap || opts.Gateway.TLSImplicitAllow { + if opts.Gateway.TLSMap || opts.Gateway.TLSAcceptKnownUrls { return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { if user == "" { return "", false } - if opts.Gateway.TLSImplicitAllow && isDNSAltName { + if opts.Gateway.TLSAcceptKnownUrls && isDNSAltName { labels := dnsAltNameLabels(user) for _, gw := range opts.Gateway.Gateways { if gw != nil && dnsAltNameMatches(labels, gw.URLs) { diff --git a/server/config_check_test.go b/server/config_check_test.go index ec82c688..2ac1e127 100644 --- a/server/config_check_test.go +++ b/server/config_check_test.go @@ -361,15 +361,15 @@ func TestConfigCheck(t *testing.T) { errorPos: 5, }, { - name: "verify_and_implicit_allow not support for clients", + name: "verify_and_accept_known_urls not support for clients", config: ` tls = { cert_file: "configs/certs/server.pem" key_file: "configs/certs/key.pem" - verify_and_implicit_allow: true + verify_and_accept_known_urls: true } `, - err: errors.New("verify_and_implicit_allow not supported in this context"), + err: errors.New("verify_and_accept_known_urls not supported in this context"), errorLine: 5, errorPos: 10, }, @@ -1154,7 +1154,7 @@ func TestConfigCheck(t *testing.T) { errorPos: 0, }, { - name: "verify_and_implicit_allow do not work for leaf nodes", + name: "verify_and_accept_known_urls do not work for leaf nodes", config: ` leafnodes { remotes = [ @@ -1162,13 +1162,13 @@ func TestConfigCheck(t *testing.T) { url: "tls://nats:7422" tls { timeout: 0.01 - verify_and_implicit_allow: true + verify_and_accept_known_urls: true } } ] }`, //Unexpected error after processing config: /var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/057996446:8:5: - err: errors.New("verify_and_implicit_allow not supported in this context"), + err: errors.New("verify_and_accept_known_urls not supported in this context"), errorLine: 8, errorPos: 5, }, @@ -1393,17 +1393,17 @@ func TestConfigCheck(t *testing.T) { errorPos: 21, }, { - name: "verify_and_implicit_allow not support for websockets", + name: "verify_and_accept_known_urls not support for websockets", config: ` websocket { tls { cert_file: "configs/certs/server.pem" key_file: "configs/certs/key.pem" - verify_and_implicit_allow: true + verify_and_accept_known_urls: true } } `, - err: fmt.Errorf("verify_and_implicit_allow not supported in this context"), + err: fmt.Errorf("verify_and_accept_known_urls not supported in this context"), errorLine: 6, errorPos: 10, }, diff --git a/server/opts.go b/server/opts.go index 11519832..eb45574e 100644 --- a/server/opts.go +++ b/server/opts.go @@ -57,21 +57,21 @@ func NoErrOnUnknownFields(noError bool) { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type ClusterOpts struct { - Name string `json:"-"` - Host string `json:"addr,omitempty"` - Port int `json:"cluster_port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - Permissions *RoutePermissions `json:"-"` - TLSTimeout float64 `json:"-"` - TLSConfig *tls.Config `json:"-"` - TLSMap bool `json:"-"` - TLSImplicitAllow bool `json:"-"` - ListenStr string `json:"-"` - Advertise string `json:"-"` - NoAdvertise bool `json:"-"` - ConnectRetries int `json:"-"` + Name string `json:"-"` + Host string `json:"addr,omitempty"` + Port int `json:"cluster_port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + Permissions *RoutePermissions `json:"-"` + TLSTimeout float64 `json:"-"` + TLSConfig *tls.Config `json:"-"` + TLSMap bool `json:"-"` + TLSAcceptKnownUrls bool `json:"-"` + ListenStr string `json:"-"` + Advertise string `json:"-"` + NoAdvertise bool `json:"-"` + ConnectRetries int `json:"-"` // Not exported (used in tests) resolver netResolver @@ -81,20 +81,20 @@ type ClusterOpts struct { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type GatewayOpts struct { - Name string `json:"name"` - Host string `json:"addr,omitempty"` - Port int `json:"port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - TLSConfig *tls.Config `json:"-"` - TLSTimeout float64 `json:"tls_timeout,omitempty"` - TLSMap bool `json:"-"` - TLSImplicitAllow bool `json:"-"` - Advertise string `json:"advertise,omitempty"` - ConnectRetries int `json:"connect_retries,omitempty"` - Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` - RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster + Name string `json:"name"` + Host string `json:"addr,omitempty"` + Port int `json:"port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + TLSConfig *tls.Config `json:"-"` + TLSTimeout float64 `json:"tls_timeout,omitempty"` + TLSMap bool `json:"-"` + TLSAcceptKnownUrls bool `json:"-"` + Advertise string `json:"advertise,omitempty"` + ConnectRetries int `json:"connect_retries,omitempty"` + Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` + RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster // Not exported, for tests. resolver netResolver @@ -399,7 +399,7 @@ type TLSConfigOpts struct { Verify bool Insecure bool Map bool - ImplicitAllow bool + AcceptKnownUrls bool Timeout float64 Ciphers []uint16 CurvePreferences []tls.CurveID @@ -1163,7 +1163,7 @@ func parseCluster(v interface{}, opts *Options, errors *[]error, warnings *[]err opts.Cluster.TLSConfig = config opts.Cluster.TLSTimeout = tlsopts.Timeout opts.Cluster.TLSMap = tlsopts.Map - opts.Cluster.TLSImplicitAllow = tlsopts.ImplicitAllow + opts.Cluster.TLSAcceptKnownUrls = tlsopts.AcceptKnownUrls case "cluster_advertise", "advertise": opts.Cluster.Advertise = mv.(string) case "no_advertise": @@ -1279,7 +1279,7 @@ func parseGateway(v interface{}, o *Options, errors *[]error, warnings *[]error) o.Gateway.TLSConfig = config o.Gateway.TLSTimeout = tlsopts.Timeout o.Gateway.TLSMap = tlsopts.Map - o.Gateway.TLSImplicitAllow = tlsopts.ImplicitAllow + o.Gateway.TLSAcceptKnownUrls = tlsopts.AcceptKnownUrls case "advertise": o.Gateway.Advertise = mv.(string) case "connect_retries": @@ -3256,18 +3256,22 @@ func parseTLS(v interface{}, isClientCtx bool) (t *TLSConfigOpts, retErr error) if !ok { return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_map' to be a boolean"} } - tc.Verify = verify + if verify { + tc.Verify = verify + } tc.Map = verify - case "verify_and_implicit_allow": + case "verify_and_accept_known_urls": verify, ok := mv.(bool) if !ok { - return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_implicit_allow' to be a boolean"} + return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_accept_known_urls' to be a boolean"} } if verify && isClientCtx { - return nil, &configErr{tk, "verify_and_implicit_allow not supported in this context"} + return nil, &configErr{tk, "verify_and_accept_known_urls not supported in this context"} } - tc.Verify = verify - tc.ImplicitAllow = verify + if verify { + tc.Verify = verify + } + tc.AcceptKnownUrls = verify case "cipher_suites": ra := mv.([]interface{}) if len(ra) == 0 { diff --git a/test/tls_test.go b/test/tls_test.go index 06933110..fa026dcb 100644 --- a/test/tls_test.go +++ b/test/tls_test.go @@ -808,7 +808,7 @@ func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" - verify_and_implicit_allow = true + verify_and_accept_known_urls = true insecure = %t timeout = 1 } @@ -879,7 +879,7 @@ func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" - verify_and_implicit_allow = true + verify_and_accept_known_urls = true insecure = %t timeout = 1 } From 8fd1b66f661d08606b345335c3ebbda9d0f8898a Mon Sep 17 00:00:00 2001 From: Matthias Hanel Date: Fri, 20 Nov 2020 16:56:44 -0500 Subject: [PATCH 5/5] Renaming to verify_cert_and_check_known_urls Signed-off-by: Matthias Hanel --- server/auth.go | 8 ++-- server/config_check_test.go | 18 ++++---- server/opts.go | 90 ++++++++++++++++++------------------- test/tls_test.go | 4 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/server/auth.go b/server/auth.go index 9b6dee97..7043b2cc 100644 --- a/server/auth.go +++ b/server/auth.go @@ -808,12 +808,12 @@ func (s *Server) isRouterAuthorized(c *client) bool { return s.opts.CustomRouterAuthentication.Check(c) } - if opts.Cluster.TLSMap || opts.Cluster.TLSAcceptKnownUrls { + if opts.Cluster.TLSMap || opts.Cluster.TLSCheckKnwonURLs { return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { if user == "" { return "", false } - if opts.Cluster.TLSAcceptKnownUrls && isDNSAltName { + if opts.Cluster.TLSCheckKnwonURLs && isDNSAltName { if dnsAltNameMatches(dnsAltNameLabels(user), opts.Routes) { return "", true } @@ -844,12 +844,12 @@ func (s *Server) isGatewayAuthorized(c *client) bool { opts := s.getOpts() // Check whether TLS map is enabled, otherwise use single user/pass. - if opts.Gateway.TLSMap || opts.Gateway.TLSAcceptKnownUrls { + if opts.Gateway.TLSMap || opts.Gateway.TLSCheckKnownURLs { return checkClientTLSCertSubject(c, func(user string, _ *ldap.DN, isDNSAltName bool) (string, bool) { if user == "" { return "", false } - if opts.Gateway.TLSAcceptKnownUrls && isDNSAltName { + if opts.Gateway.TLSCheckKnownURLs && isDNSAltName { labels := dnsAltNameLabels(user) for _, gw := range opts.Gateway.Gateways { if gw != nil && dnsAltNameMatches(labels, gw.URLs) { diff --git a/server/config_check_test.go b/server/config_check_test.go index 2ac1e127..166aa761 100644 --- a/server/config_check_test.go +++ b/server/config_check_test.go @@ -361,15 +361,15 @@ func TestConfigCheck(t *testing.T) { errorPos: 5, }, { - name: "verify_and_accept_known_urls not support for clients", + name: "verify_cert_and_check_known_urls not support for clients", config: ` tls = { cert_file: "configs/certs/server.pem" key_file: "configs/certs/key.pem" - verify_and_accept_known_urls: true + verify_cert_and_check_known_urls: true } `, - err: errors.New("verify_and_accept_known_urls not supported in this context"), + err: errors.New("verify_cert_and_check_known_urls not supported in this context"), errorLine: 5, errorPos: 10, }, @@ -1154,7 +1154,7 @@ func TestConfigCheck(t *testing.T) { errorPos: 0, }, { - name: "verify_and_accept_known_urls do not work for leaf nodes", + name: "verify_cert_and_check_known_urls do not work for leaf nodes", config: ` leafnodes { remotes = [ @@ -1162,13 +1162,13 @@ func TestConfigCheck(t *testing.T) { url: "tls://nats:7422" tls { timeout: 0.01 - verify_and_accept_known_urls: true + verify_cert_and_check_known_urls: true } } ] }`, //Unexpected error after processing config: /var/folders/9h/6g_c9l6n6bb8gp331d_9y0_w0000gn/T/057996446:8:5: - err: errors.New("verify_and_accept_known_urls not supported in this context"), + err: errors.New("verify_cert_and_check_known_urls not supported in this context"), errorLine: 8, errorPos: 5, }, @@ -1393,17 +1393,17 @@ func TestConfigCheck(t *testing.T) { errorPos: 21, }, { - name: "verify_and_accept_known_urls not support for websockets", + name: "verify_cert_and_check_known_urls not support for websockets", config: ` websocket { tls { cert_file: "configs/certs/server.pem" key_file: "configs/certs/key.pem" - verify_and_accept_known_urls: true + verify_cert_and_check_known_urls: true } } `, - err: fmt.Errorf("verify_and_accept_known_urls not supported in this context"), + err: fmt.Errorf("verify_cert_and_check_known_urls not supported in this context"), errorLine: 6, errorPos: 10, }, diff --git a/server/opts.go b/server/opts.go index eb45574e..32802133 100644 --- a/server/opts.go +++ b/server/opts.go @@ -57,21 +57,21 @@ func NoErrOnUnknownFields(noError bool) { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type ClusterOpts struct { - Name string `json:"-"` - Host string `json:"addr,omitempty"` - Port int `json:"cluster_port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - Permissions *RoutePermissions `json:"-"` - TLSTimeout float64 `json:"-"` - TLSConfig *tls.Config `json:"-"` - TLSMap bool `json:"-"` - TLSAcceptKnownUrls bool `json:"-"` - ListenStr string `json:"-"` - Advertise string `json:"-"` - NoAdvertise bool `json:"-"` - ConnectRetries int `json:"-"` + Name string `json:"-"` + Host string `json:"addr,omitempty"` + Port int `json:"cluster_port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + Permissions *RoutePermissions `json:"-"` + TLSTimeout float64 `json:"-"` + TLSConfig *tls.Config `json:"-"` + TLSMap bool `json:"-"` + TLSCheckKnwonURLs bool `json:"-"` + ListenStr string `json:"-"` + Advertise string `json:"-"` + NoAdvertise bool `json:"-"` + ConnectRetries int `json:"-"` // Not exported (used in tests) resolver netResolver @@ -81,20 +81,20 @@ type ClusterOpts struct { // NOTE: This structure is no longer used for monitoring endpoints // and json tags are deprecated and may be removed in the future. type GatewayOpts struct { - Name string `json:"name"` - Host string `json:"addr,omitempty"` - Port int `json:"port,omitempty"` - Username string `json:"-"` - Password string `json:"-"` - AuthTimeout float64 `json:"auth_timeout,omitempty"` - TLSConfig *tls.Config `json:"-"` - TLSTimeout float64 `json:"tls_timeout,omitempty"` - TLSMap bool `json:"-"` - TLSAcceptKnownUrls bool `json:"-"` - Advertise string `json:"advertise,omitempty"` - ConnectRetries int `json:"connect_retries,omitempty"` - Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` - RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster + Name string `json:"name"` + Host string `json:"addr,omitempty"` + Port int `json:"port,omitempty"` + Username string `json:"-"` + Password string `json:"-"` + AuthTimeout float64 `json:"auth_timeout,omitempty"` + TLSConfig *tls.Config `json:"-"` + TLSTimeout float64 `json:"tls_timeout,omitempty"` + TLSMap bool `json:"-"` + TLSCheckKnownURLs bool `json:"-"` + Advertise string `json:"advertise,omitempty"` + ConnectRetries int `json:"connect_retries,omitempty"` + Gateways []*RemoteGatewayOpts `json:"gateways,omitempty"` + RejectUnknown bool `json:"reject_unknown,omitempty"` // config got renamed to reject_unknown_cluster // Not exported, for tests. resolver netResolver @@ -393,16 +393,16 @@ type authorization struct { // TLSConfigOpts holds the parsed tls config information, // used with flag parsing type TLSConfigOpts struct { - CertFile string - KeyFile string - CaFile string - Verify bool - Insecure bool - Map bool - AcceptKnownUrls bool - Timeout float64 - Ciphers []uint16 - CurvePreferences []tls.CurveID + CertFile string + KeyFile string + CaFile string + Verify bool + Insecure bool + Map bool + TLSCheckKnownURLs bool + Timeout float64 + Ciphers []uint16 + CurvePreferences []tls.CurveID } var tlsUsage = ` @@ -1163,7 +1163,7 @@ func parseCluster(v interface{}, opts *Options, errors *[]error, warnings *[]err opts.Cluster.TLSConfig = config opts.Cluster.TLSTimeout = tlsopts.Timeout opts.Cluster.TLSMap = tlsopts.Map - opts.Cluster.TLSAcceptKnownUrls = tlsopts.AcceptKnownUrls + opts.Cluster.TLSCheckKnwonURLs = tlsopts.TLSCheckKnownURLs case "cluster_advertise", "advertise": opts.Cluster.Advertise = mv.(string) case "no_advertise": @@ -1279,7 +1279,7 @@ func parseGateway(v interface{}, o *Options, errors *[]error, warnings *[]error) o.Gateway.TLSConfig = config o.Gateway.TLSTimeout = tlsopts.Timeout o.Gateway.TLSMap = tlsopts.Map - o.Gateway.TLSAcceptKnownUrls = tlsopts.AcceptKnownUrls + o.Gateway.TLSCheckKnownURLs = tlsopts.TLSCheckKnownURLs case "advertise": o.Gateway.Advertise = mv.(string) case "connect_retries": @@ -3260,18 +3260,18 @@ func parseTLS(v interface{}, isClientCtx bool) (t *TLSConfigOpts, retErr error) tc.Verify = verify } tc.Map = verify - case "verify_and_accept_known_urls": + case "verify_cert_and_check_known_urls": verify, ok := mv.(bool) if !ok { - return nil, &configErr{tk, "error parsing tls config, expected 'verify_and_accept_known_urls' to be a boolean"} + return nil, &configErr{tk, "error parsing tls config, expected 'verify_cert_and_check_known_urls' to be a boolean"} } if verify && isClientCtx { - return nil, &configErr{tk, "verify_and_accept_known_urls not supported in this context"} + return nil, &configErr{tk, "verify_cert_and_check_known_urls not supported in this context"} } if verify { tc.Verify = verify } - tc.AcceptKnownUrls = verify + tc.TLSCheckKnownURLs = verify case "cipher_suites": ra := mv.([]interface{}) if len(ra) == 0 { diff --git a/test/tls_test.go b/test/tls_test.go index fa026dcb..17ceac39 100644 --- a/test/tls_test.go +++ b/test/tls_test.go @@ -808,7 +808,7 @@ func testTLSRoutesCertificateImplicitAllow(t *testing.T, pass bool) { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" - verify_and_accept_known_urls = true + verify_cert_and_check_known_urls = true insecure = %t timeout = 1 } @@ -879,7 +879,7 @@ func testTLSGatewaysCertificateImplicitAllow(t *testing.T, pass bool) { cert_file = "./configs/certs/tlsauth/server.pem" key_file = "./configs/certs/tlsauth/server-key.pem" ca_file = "./configs/certs/tlsauth/ca.pem" - verify_and_accept_known_urls = true + verify_cert_and_check_known_urls = true insecure = %t timeout = 1 }