[arvados] created: 2.5.0-3-g37710c707

git repository hosting git at public.arvados.org
Wed Jan 4 23:36:23 UTC 2023


        at  37710c707e0f7b0a57a836ff8cc42dd0c5f762ff (commit)


commit 37710c707e0f7b0a57a836ff8cc42dd0c5f762ff
Author: Tom Clegg <tom at curii.com>
Date:   Wed Jan 4 18:35:03 2023 -0500

    19896: Configurable minimum TLS version for LDAP connection.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curii.com>

diff --git a/lib/config/config.default.yml b/lib/config/config.default.yml
index 2d9119adf..3ca137e9c 100644
--- a/lib/config/config.default.yml
+++ b/lib/config/config.default.yml
@@ -803,6 +803,12 @@ Clusters:
         # Skip TLS certificate name verification.
         InsecureTLS: false
 
+        # Mininum TLS version to negotiate when connecting to server
+        # (ldaps://... or StartTLS). It may be necessary to set this
+        # to "1.1" for compatibility with older LDAP servers. If
+        # blank, use the recommended minimum version (1.2).
+        MinTLSVersion: ""
+
         # Strip the @domain part if a user supplies an email-style
         # username with this domain. If "*", strip any user-provided
         # domain. If "", never strip the domain part. Example:
diff --git a/lib/config/export.go b/lib/config/export.go
index 069e300c5..dfd62ce04 100644
--- a/lib/config/export.go
+++ b/lib/config/export.go
@@ -162,6 +162,7 @@ var whitelist = map[string]bool{
 	"Login.LDAP.EmailAttribute":                           false,
 	"Login.LDAP.Enable":                                   true,
 	"Login.LDAP.InsecureTLS":                              false,
+	"Login.LDAP.MinTLSVersion":                            false,
 	"Login.LDAP.SearchAttribute":                          false,
 	"Login.LDAP.SearchBase":                               false,
 	"Login.LDAP.SearchBindPassword":                       false,
diff --git a/lib/controller/localdb/login_ldap.go b/lib/controller/localdb/login_ldap.go
index 3f13c7b27..f8fe9084d 100644
--- a/lib/controller/localdb/login_ldap.go
+++ b/lib/controller/localdb/login_ldap.go
@@ -47,7 +47,25 @@ func (ctrl *ldapLoginController) UserAuthenticate(ctx context.Context, opts arva
 	}
 
 	log = log.WithField("URL", conf.URL.String())
-	l, err := ldap.DialURL(conf.URL.String())
+	var l *ldap.Conn
+	var err error
+	if conf.URL.Scheme == "ldaps" {
+		// ldap.DialURL does not currently allow us to control
+		// tls.Config, so we need to figure out the port
+		// ourselves and call DialTLS.
+		host, port, err := net.SplitHostPort(conf.URL.Host)
+		if err != nil {
+			// Assume error means no port given
+			host = conf.URL.Host
+			port = ldap.DefaultLdapsPort
+		}
+		l, err = ldap.DialTLS("tcp", net.JoinHostPort(host, port), &tls.Config{
+			ServerName: host,
+			MinVersion: uint16(conf.MinTLSVersion),
+		})
+	} else {
+		l, err = ldap.DialURL(conf.URL.String())
+	}
 	if err != nil {
 		log.WithError(err).Error("ldap connection failed")
 		return arvados.APIClientAuthorization{}, err
@@ -58,6 +76,7 @@ func (ctrl *ldapLoginController) UserAuthenticate(ctx context.Context, opts arva
 		var tlsconfig tls.Config
 		if conf.InsecureTLS {
 			tlsconfig.InsecureSkipVerify = true
+			tlsconfig.MinVersion = uint16(conf.MinTLSVersion)
 		} else {
 			if host, _, err := net.SplitHostPort(conf.URL.Host); err != nil {
 				// Assume SplitHostPort error means
diff --git a/sdk/go/arvados/config.go b/sdk/go/arvados/config.go
index fbbcb78ec..51e74edb7 100644
--- a/sdk/go/arvados/config.go
+++ b/sdk/go/arvados/config.go
@@ -5,6 +5,7 @@
 package arvados
 
 import (
+	"crypto/tls"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -162,6 +163,7 @@ type Cluster struct {
 			URL                URL
 			StartTLS           bool
 			InsecureTLS        bool
+			MinTLSVersion      TLSVersion
 			StripDomain        string
 			AppendDomain       string
 			SearchAttribute    string
@@ -404,6 +406,51 @@ func (su URL) String() string {
 	return (*url.URL)(&su).String()
 }
 
+type TLSVersion uint16
+
+func (v TLSVersion) MarshalText() ([]byte, error) {
+	switch v {
+	case 0:
+		return []byte{}, nil
+	case tls.VersionTLS10:
+		return []byte("1.0"), nil
+	case tls.VersionTLS11:
+		return []byte("1.1"), nil
+	case tls.VersionTLS12:
+		return []byte("1.2"), nil
+	case tls.VersionTLS13:
+		return []byte("1.3"), nil
+	default:
+		return nil, fmt.Errorf("unsupported TLSVersion %x", v)
+	}
+}
+
+func (v *TLSVersion) UnmarshalJSON(text []byte) error {
+	if len(text) > 0 && text[0] == '"' {
+		var s string
+		err := json.Unmarshal(text, &s)
+		if err != nil {
+			return err
+		}
+		text = []byte(s)
+	}
+	switch string(text) {
+	case "":
+		*v = 0
+	case "1.0":
+		*v = tls.VersionTLS10
+	case "1.1":
+		*v = tls.VersionTLS11
+	case "1.2":
+		*v = tls.VersionTLS12
+	case "1.3":
+		*v = tls.VersionTLS13
+	default:
+		return fmt.Errorf("unsupported TLSVersion %q", text)
+	}
+	return nil
+}
+
 type ServiceInstance struct {
 	ListenURL  URL
 	Rendezvous string `json:",omitempty"`
diff --git a/sdk/go/arvados/config_test.go b/sdk/go/arvados/config_test.go
index 58f4b961b..3c65643be 100644
--- a/sdk/go/arvados/config_test.go
+++ b/sdk/go/arvados/config_test.go
@@ -5,6 +5,7 @@
 package arvados
 
 import (
+	"crypto/tls"
 	"encoding/json"
 
 	"github.com/ghodss/yaml"
@@ -71,3 +72,19 @@ func (s *ConfigSuite) TestURLTrailingSlash(c *check.C) {
 	json.Unmarshal([]byte(`{"https://foo.example/": true}`), &b)
 	c.Check(a, check.DeepEquals, b)
 }
+
+func (s *ConfigSuite) TestTLSVersion(c *check.C) {
+	var v struct {
+		Version TLSVersion
+	}
+	err := json.Unmarshal([]byte(`{"Version": 1.0}`), &v)
+	c.Check(err, check.IsNil)
+	c.Check(v.Version, check.Equals, TLSVersion(tls.VersionTLS10))
+
+	err = json.Unmarshal([]byte(`{"Version": "1.3"}`), &v)
+	c.Check(err, check.IsNil)
+	c.Check(v.Version, check.Equals, TLSVersion(tls.VersionTLS13))
+
+	err = json.Unmarshal([]byte(`{"Version": "1.345"}`), &v)
+	c.Check(err, check.NotNil)
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list