Skip to content

Commit c1e788b

Browse files
benweissmannofekshenawa
authored andcommitted
feat: add TLS URL parameters
1 parent b566dca commit c1e788b

File tree

4 files changed

+118
-1
lines changed

4 files changed

+118
-1
lines changed

options.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,36 @@ func setupConnParams(u *url.URL, o *Options) (*Options, error) {
575575
} else {
576576
o.ConnMaxLifetime = q.duration("max_conn_age")
577577
}
578+
579+
if u.Scheme == "rediss" {
580+
tlsCertPEMFile := q.string("TLSCertPEMFile")
581+
tlsKeyPEMFile := q.string("TLSKeyPEMFile")
582+
583+
if (tlsCertPEMFile == "") != (tlsKeyPEMFile == "") {
584+
return nil, fmt.Errorf("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted")
585+
}
586+
587+
if tlsCertPEMFile != "" {
588+
cert, certLoadErr := tls.LoadX509KeyPair(tlsCertPEMFile, tlsKeyPEMFile)
589+
if certLoadErr != nil {
590+
return nil, fmt.Errorf("redis: Error loading X509 Key Pair: %w", certLoadErr)
591+
}
592+
593+
o.TLSConfig.Certificates = []tls.Certificate{cert}
594+
}
595+
596+
o.TLSConfig.MinVersion = uint16(q.int("TLSMinVersion"))
597+
o.TLSConfig.MaxVersion = uint16(q.int("TLSMaxVersion"))
598+
o.TLSConfig.InsecureSkipVerify = q.bool("TLSInsecureSkipVerify")
599+
600+
serverNameOverride := q.string("ServerName")
601+
if serverNameOverride != "" {
602+
// we explicitly check for this query parameter, so we don't overwrite
603+
// the default server name (the hostname of the Redis server) if it's
604+
// not given
605+
o.TLSConfig.ServerName = serverNameOverride
606+
}
607+
}
578608
if q.err != nil {
579609
return nil, q.err
580610
}

options_test.go

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ import (
1010
)
1111

1212
func TestParseURL(t *testing.T) {
13+
certPem := []byte(`-----BEGIN CERTIFICATE-----
14+
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
15+
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
16+
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
17+
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
18+
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
19+
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
20+
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
21+
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
22+
6MF9+Yw1Yy0t
23+
-----END CERTIFICATE-----`)
24+
keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
25+
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
26+
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
27+
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
28+
-----END EC PRIVATE KEY-----`)
29+
testCert, err := tls.X509KeyPair(certPem, keyPem)
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
1334
cases := []struct {
1435
url string
1536
o *Options // expected value
@@ -29,7 +50,24 @@ func TestParseURL(t *testing.T) {
2950
o: &Options{Addr: "12345:6379"},
3051
}, {
3152
url: "rediss://localhost:123",
32-
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ /* no deep comparison */ }},
53+
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "localhost"}},
54+
}, {
55+
url: "rediss://localhost:123?ServerName=abc&TLSMinVersion=1&TLSMaxVersion=3&TLSInsecureSkipVerify=true",
56+
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc", MinVersion: 1, MaxVersion: 3, InsecureSkipVerify: true}},
57+
}, {
58+
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/testcert.pem&TLSKeyPEMFile=./testdata/testkey.pem",
59+
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "localhost", Certificates: []tls.Certificate{testCert}}},
60+
}, {
61+
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/doesnotexist.pem&TLSKeyPEMFile=./testdata/testkey.pem",
62+
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc"}},
63+
err: errors.New("redis: Error loading X509 Key Pair: open ./testdata/doesnotexist.pem: no such file or directory"),
64+
}, {
65+
url: "rediss://localhost:123?TLSCertPEMFile=./testdata/testcert.pem",
66+
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{ServerName: "abc"}},
67+
err: errors.New("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted"),
68+
}, {
69+
url: "rediss://localhost:123?TLSKeyPEMFile=./testdata/testkey.pem",
70+
err: errors.New("redis: TLSCertPEMFile and TLSKeyPEMFile URL parameters must be both set or both omitted"),
3371
}, {
3472
url: "rediss://localhost:123/?skip_verify=true",
3573
o: &Options{Addr: "localhost:123", TLSConfig: &tls.Config{InsecureSkipVerify: true}},
@@ -197,6 +235,39 @@ func comprareOptions(t *testing.T, actual, expected *Options) {
197235
if actual.ConnMaxLifetime != expected.ConnMaxLifetime {
198236
t.Errorf("ConnMaxLifetime: got %v, expected %v", actual.ConnMaxLifetime, expected.ConnMaxLifetime)
199237
}
238+
239+
if (actual.TLSConfig == nil) != (expected.TLSConfig == nil) {
240+
t.Errorf("TLSConfig nil: got %v, expected %v", actual.TLSConfig == nil, expected.TLSConfig == nil)
241+
}
242+
243+
if (actual.TLSConfig != nil) && (expected.TLSConfig != nil) {
244+
if actual.TLSConfig.MinVersion != expected.TLSConfig.MinVersion {
245+
t.Errorf("TLSConfig.MinVersion: got %v, expected %v", actual.TLSConfig.MinVersion, expected.TLSConfig.MinVersion)
246+
}
247+
248+
if actual.TLSConfig.MaxVersion != expected.TLSConfig.MaxVersion {
249+
t.Errorf("TLSConfig.MaxVersion: got %v, expected %v", actual.TLSConfig.MaxVersion, expected.TLSConfig.MaxVersion)
250+
}
251+
252+
if actual.TLSConfig.ServerName != expected.TLSConfig.ServerName {
253+
t.Errorf("TLSConfig.ServerName: got %v, expected %v", actual.TLSConfig.ServerName, expected.TLSConfig.ServerName)
254+
}
255+
256+
if actual.TLSConfig.InsecureSkipVerify != expected.TLSConfig.InsecureSkipVerify {
257+
t.Errorf("TLSConfig.InsecureSkipVerify: got %v, expected %v", actual.TLSConfig.InsecureSkipVerify, expected.TLSConfig.InsecureSkipVerify)
258+
}
259+
260+
if len(actual.TLSConfig.Certificates) != len(expected.TLSConfig.Certificates) {
261+
t.Errorf("TLSConfig.Certificates: got %v, expected %v", actual.TLSConfig.Certificates, expected.TLSConfig.Certificates)
262+
}
263+
264+
for i, actualCert := range actual.TLSConfig.Certificates {
265+
expectedCert := expected.TLSConfig.Certificates[i]
266+
if !actualCert.Leaf.Equal(expectedCert.Leaf) {
267+
t.Errorf("TLSConfig.Certificates[%d].Leaf: got %v, expected %v", i, actual.TLSConfig.Certificates, expected.TLSConfig.Certificates)
268+
}
269+
}
270+
}
200271
}
201272

202273
// Test ReadTimeout option initialization, including special values -1 and 0.

testdata/testcert.pem

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
3+
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
4+
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
5+
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
6+
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
7+
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
8+
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
9+
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
10+
6MF9+Yw1Yy0t
11+
-----END CERTIFICATE-----

testdata/testkey.pem

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-----BEGIN EC PRIVATE KEY-----
2+
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
3+
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
4+
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
5+
-----END EC PRIVATE KEY-----

0 commit comments

Comments
 (0)