mirror of https://github.com/go-redis/redis.git
feat: add TLS URL parameters
This commit is contained in:
parent
4c8b4d1619
commit
fae038dbdd
31
options.go
31
options.go
|
@ -390,6 +390,37 @@ func setupConnParams(u *url.URL, o *Options) (*Options, error) {
|
||||||
o.PoolTimeout = q.duration("pool_timeout")
|
o.PoolTimeout = q.duration("pool_timeout")
|
||||||
o.IdleTimeout = q.duration("idle_timeout")
|
o.IdleTimeout = q.duration("idle_timeout")
|
||||||
o.IdleCheckFrequency = q.duration("idle_check_frequency")
|
o.IdleCheckFrequency = q.duration("idle_check_frequency")
|
||||||
|
|
||||||
|
if u.Scheme == "rediss" {
|
||||||
|
tlsCertPEMFile := q.string("TLSCertPEMFile")
|
||||||
|
tlsKeyPEMFile := q.string("TLSKeyPEMFile")
|
||||||
|
|
||||||
|
if (tlsCertPEMFile == "") != (tlsKeyPEMFile == "") {
|
||||||
|
return nil, fmt.Errorf("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tlsCertPEMFile != "" {
|
||||||
|
cert, certLoadErr := tls.LoadX509KeyPair(tlsCertPEMFile, tlsKeyPEMFile)
|
||||||
|
if certLoadErr != nil {
|
||||||
|
return nil, fmt.Errorf("redis: Error loading X509 Key Pair: %w", certLoadErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
o.TLSConfig.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
|
||||||
|
o.TLSConfig.MinVersion = uint16(q.int("TLSMinVersion"))
|
||||||
|
o.TLSConfig.MaxVersion = uint16(q.int("TLSMaxVersion"))
|
||||||
|
o.TLSConfig.InsecureSkipVerify = q.bool("TLSInsecureSkipVerify")
|
||||||
|
|
||||||
|
serverNameOverride := q.string("ServerName")
|
||||||
|
if serverNameOverride != "" {
|
||||||
|
// we explicitly check for this query parameter, so we don't overwrite
|
||||||
|
// the default server name (the hostname of the Redis server) if it's
|
||||||
|
// not given
|
||||||
|
o.TLSConfig.ServerName = serverNameOverride
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if q.err != nil {
|
if q.err != nil {
|
||||||
return nil, q.err
|
return nil, q.err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,27 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseURL(t *testing.T) {
|
func TestParseURL(t *testing.T) {
|
||||||
|
certPem := []byte(`-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
|
||||||
|
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
|
||||||
|
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
|
||||||
|
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
|
||||||
|
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
|
||||||
|
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
|
||||||
|
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
|
||||||
|
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
|
||||||
|
6MF9+Yw1Yy0t
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
|
||||||
|
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
|
||||||
|
-----END EC PRIVATE KEY-----`)
|
||||||
|
testCert, err := tls.X509KeyPair(certPem, keyPem)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
url string
|
url string
|
||||||
o *Options // expected value
|
o *Options // expected value
|
||||||
|
@ -30,7 +51,24 @@ func TestParseURL(t *testing.T) {
|
||||||
o: &Options{Addr: "12345:6379"},
|
o: &Options{Addr: "12345:6379"},
|
||||||
}, {
|
}, {
|
||||||
url: "rediss://localhost:123",
|
url: "rediss://localhost:123",
|
||||||
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ /* no deep comparison */ }},
|
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "localhost"}},
|
||||||
|
}, {
|
||||||
|
url: "rediss://localhost:123?ServerName=abc&TLSMinVersion=1&TLSMaxVersion=3&TLSInsecureSkipVerify=true",
|
||||||
|
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc", MinVersion: 1, MaxVersion: 3, InsecureSkipVerify: true}},
|
||||||
|
}, {
|
||||||
|
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/testcert.pem&TLSKeyPEMFile=./testdata/testkey.pem",
|
||||||
|
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "localhost", Certificates: []tls.Certificate{testCert}}},
|
||||||
|
}, {
|
||||||
|
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/doesnotexist.pem&TLSKeyPEMFile=./testdata/testkey.pem",
|
||||||
|
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc"}},
|
||||||
|
err: errors.New("redis: Error loading X509 Key Pair: open ./testdata/doesnotexist.pem: no such file or directory"),
|
||||||
|
}, {
|
||||||
|
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/testcert.pem",
|
||||||
|
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc"}},
|
||||||
|
err: errors.New("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted"),
|
||||||
|
}, {
|
||||||
|
url: "rediss://localhost:123?TLSKeyPEMFile=./testdata/testkey.pem",
|
||||||
|
err: errors.New("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted"),
|
||||||
}, {
|
}, {
|
||||||
url: "redis://:bar@localhost:123",
|
url: "redis://:bar@localhost:123",
|
||||||
o: &Options{Addr: "localhost:123", Password: "bar"},
|
o: &Options{Addr: "localhost:123", Password: "bar"},
|
||||||
|
@ -189,6 +227,39 @@ func comprareOptions(t *testing.T, actual, expected *Options) {
|
||||||
if actual.IdleCheckFrequency != expected.IdleCheckFrequency {
|
if actual.IdleCheckFrequency != expected.IdleCheckFrequency {
|
||||||
t.Errorf("IdleCheckFrequency: got %v, expected %v", actual.IdleCheckFrequency, expected.IdleCheckFrequency)
|
t.Errorf("IdleCheckFrequency: got %v, expected %v", actual.IdleCheckFrequency, expected.IdleCheckFrequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (actual.TLSConfig == nil) != (expected.TLSConfig == nil) {
|
||||||
|
t.Errorf("TLSConfig nil: got %v, expected %v", actual.TLSConfig == nil, expected.TLSConfig == nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actual.TLSConfig != nil) && (expected.TLSConfig != nil) {
|
||||||
|
if actual.TLSConfig.MinVersion != expected.TLSConfig.MinVersion {
|
||||||
|
t.Errorf("TLSConfig.MinVersion: got %v, expected %v", actual.TLSConfig.MinVersion, expected.TLSConfig.MinVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual.TLSConfig.MaxVersion != expected.TLSConfig.MaxVersion {
|
||||||
|
t.Errorf("TLSConfig.MaxVersion: got %v, expected %v", actual.TLSConfig.MaxVersion, expected.TLSConfig.MaxVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual.TLSConfig.ServerName != expected.TLSConfig.ServerName {
|
||||||
|
t.Errorf("TLSConfig.ServerName: got %v, expected %v", actual.TLSConfig.ServerName, expected.TLSConfig.ServerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if actual.TLSConfig.InsecureSkipVerify != expected.TLSConfig.InsecureSkipVerify {
|
||||||
|
t.Errorf("TLSConfig.InsecureSkipVerify: got %v, expected %v", actual.TLSConfig.InsecureSkipVerify, expected.TLSConfig.InsecureSkipVerify)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(actual.TLSConfig.Certificates) != len(expected.TLSConfig.Certificates) {
|
||||||
|
t.Errorf("TLSConfig.Certificates: got %v, expected %v", actual.TLSConfig.Certificates, expected.TLSConfig.Certificates)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, actualCert := range actual.TLSConfig.Certificates {
|
||||||
|
expectedCert := expected.TLSConfig.Certificates[i]
|
||||||
|
if !actualCert.Leaf.Equal(expectedCert.Leaf) {
|
||||||
|
t.Errorf("TLSConfig.Certificates[%d].Leaf: got %v, expected %v", i, actual.TLSConfig.Certificates, expected.TLSConfig.Certificates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test ReadTimeout option initialization, including special values -1 and 0.
|
// Test ReadTimeout option initialization, including special values -1 and 0.
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
|
||||||
|
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
|
||||||
|
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
|
||||||
|
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
|
||||||
|
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
|
||||||
|
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
|
||||||
|
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
|
||||||
|
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
|
||||||
|
6MF9+Yw1Yy0t
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN EC PRIVATE KEY-----
|
||||||
|
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
|
||||||
|
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
|
||||||
|
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
|
||||||
|
-----END EC PRIVATE KEY-----
|
Loading…
Reference in New Issue