git.iko.soy/typeable/oauth2-proxy
on master help sign in
Initalize TLS.Config when connecting to Redis with TLS (#1296)

* init TLS.Config when connecting to Redis with TLS * don't overwrite TLS config if it exists * add tests for Redis with TLS * remove hardcoded certs * add GenerateCert func * use GenerateCert util func * fix issue reported by go fmt * limit return statements in GenerateCert

commitb49e62f9b23ea1f5fb7af46b57eef7b27bcc2e57 authorMaciej Strzelecki <mstrzele@users.noreply.github.com> dateTue 19 Oct 2021, 10:17 (5 years ago) parentea261ca
7 files changed+167−33
CHANGELOG.md+1 pkg/http/http_suite_test.go+6−33 pkg/sessions/redis/redis_store.go+11 pkg/sessions/redis/redis_store_test.go+104 pkg/util/util.go+43 watcher.go+1 watcher_unsupported.go+1
CHANGELOG.md+1
@@ -47,6 +47,7 @@
4747- [#1357](https://github.com/oauth2-proxy/oauth2-proxy/pull/1357) Fix unsafe access to session variable (@harzallah)
4848- [#997](https://github.com/oauth2-proxy/oauth2-proxy/pull/997) Allow passing the raw url path when proxying upstream requests - e.g. /%2F/ (@FStelzer)
4949- [#1147](https://github.com/oauth2-proxy/oauth2-proxy/pull/1147) Multiarch support for docker image (@goshlanguage)
50+- [#1296](https://github.com/oauth2-proxy/oauth2-proxy/pull/1296) Fixed `panic` when connecting to Redis with TLS (@mstrzele)
5051
5152# V7.1.3
5253
pkg/http/http_suite_test.go+6−33
@@ -2,20 +2,15 @@ package http
22
33import (
44 "bytes"
5− "crypto/rand"
6− "crypto/rsa"
75 "crypto/tls"
86 "crypto/x509"
9− "crypto/x509/pkix"
107 "encoding/pem"
11− "math/big"
12− "net"
138 "net/http"
149 "testing"
15− "time"
1610
1711 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
1812 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
13+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
1914 . "github.com/onsi/ginkgo"
2015 . "github.com/onsi/gomega"
2116)
@@ -34,38 +29,16 @@ func TestHTTPSuite(t *testing.T) {
3429
3530var _ = BeforeSuite(func() {
3631 By("Generating a self-signed cert for TLS tests", func() {
37− priv, err := rsa.GenerateKey(rand.Reader, 2048)
38− Expect(err).ToNot(HaveOccurred())
39−
40− keyOut := bytes.NewBuffer(nil)
41− privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
42− Expect(err).ToNot(HaveOccurred())
43− Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes})).To(Succeed())
44− keyDataSource.Value = keyOut.Bytes()
45−
46− serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
47− serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
48− Expect(err).ToNot(HaveOccurred())
49−
50− template := x509.Certificate{
51− SerialNumber: serialNumber,
52− Subject: pkix.Name{
53− Organization: []string{"OAuth2 Proxy Test Suite"},
54− },
55− NotBefore: time.Now(),
56− NotAfter: time.Now().Add(time.Hour),
57− IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
58− KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
59− ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
60− }
61−
62− certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
32+ certBytes, keyBytes, err := util.GenerateCert()
6333 Expect(err).ToNot(HaveOccurred())
6434 certData = certBytes
6535
66− certOut := bytes.NewBuffer(nil)
36+ certOut := new(bytes.Buffer)
6737 Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
6838 certDataSource.Value = certOut.Bytes()
39+ keyOut := new(bytes.Buffer)
40+ Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
41+ keyDataSource.Value = keyOut.Bytes()
6942 })
7043
7144 By("Setting up a http client", func() {
pkg/sessions/redis/redis_store.go+11
@@ -2,6 +2,7 @@ package redis
22
33import (
44 "context"
5+ "crypto/tls"
56 "crypto/x509"
67 "fmt"
78 "io/ioutil"
@@ -127,6 +128,11 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
127128 }
128129
129130 if opts.InsecureSkipTLSVerify {
131+ if opt.TLSConfig == nil {
132+ /* #nosec */
133+ opt.TLSConfig = &tls.Config{}
134+ }
135+
130136 opt.TLSConfig.InsecureSkipVerify = true
131137 }
132138
@@ -148,6 +154,11 @@ func buildStandaloneClient(opts options.RedisStoreOptions) (Client, error) {
148154 logger.Errorf("no certs appended, using system certs only")
149155 }
150156
157+ if opt.TLSConfig == nil {
158+ /* #nosec */
159+ opt.TLSConfig = &tls.Config{}
160+ }
161+
151162 opt.TLSConfig.RootCAs = rootCAs
152163 }
153164
pkg/sessions/redis/redis_store_test.go+104
@@ -1,7 +1,10 @@
11package redis
22
33import (
4+ "bytes"
45 "context"
6+ "crypto/tls"
7+ "encoding/pem"
58 "log"
69 "os"
710 "testing"
@@ -15,6 +18,7 @@ import (
1518 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
1619 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/persistence"
1720 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/tests"
21+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
1822 . "github.com/onsi/ginkgo"
1923 . "github.com/onsi/gomega"
2024)
@@ -224,4 +228,104 @@ var _ = Describe("Redis SessionStore Tests", func() {
224228 )
225229 })
226230 })
231+
232+ Context("with custom CA path", func() {
233+ var caPath string
234+
235+ BeforeEach(func() {
236+ certBytes, keyBytes, err := util.GenerateCert()
237+ Expect(err).ToNot(HaveOccurred())
238+ certOut := new(bytes.Buffer)
239+ Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
240+ certData := certOut.Bytes()
241+ keyOut := new(bytes.Buffer)
242+ Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
243+ cert, err := tls.X509KeyPair(certData, keyOut.Bytes())
244+ Expect(err).ToNot(HaveOccurred())
245+
246+ certFile, err := os.CreateTemp("", "cert.*.pem")
247+ Expect(err).ToNot(HaveOccurred())
248+ caPath = certFile.Name()
249+ _, err = certFile.Write(certData)
250+ defer certFile.Close()
251+ Expect(err).ToNot(HaveOccurred())
252+
253+ mr.Close()
254+
255+ mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
256+ Expect(err).ToNot(HaveOccurred())
257+ })
258+
259+ AfterEach(func() {
260+ Expect(os.Remove(caPath)).ToNot(HaveOccurred())
261+
262+ mr.Close()
263+
264+ var err error
265+ mr, err = miniredis.Run()
266+ Expect(err).ToNot(HaveOccurred())
267+ })
268+
269+ tests.RunSessionStoreTests(
270+ func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
271+ // Set the connection URL
272+ opts.Type = options.RedisSessionStoreType
273+ opts.Redis.ConnectionURL = "redis://" + mr.Addr()
274+ opts.Redis.CAPath = caPath
275+
276+ // Capture the session store so that we can close the client
277+ var err error
278+ ss, err = NewRedisSessionStore(opts, cookieOpts)
279+ return ss, err
280+ },
281+ func(d time.Duration) error {
282+ mr.FastForward(d)
283+ return nil
284+ },
285+ )
286+ })
287+
288+ Context("with insecure TLS connection", func() {
289+ BeforeEach(func() {
290+ certBytes, keyBytes, err := util.GenerateCert()
291+ Expect(err).ToNot(HaveOccurred())
292+ certOut := new(bytes.Buffer)
293+ Expect(pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes})).To(Succeed())
294+ keyOut := new(bytes.Buffer)
295+ Expect(pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: keyBytes})).To(Succeed())
296+ cert, err := tls.X509KeyPair(certOut.Bytes(), keyOut.Bytes())
297+ Expect(err).ToNot(HaveOccurred())
298+
299+ mr.Close()
300+
301+ mr, err = miniredis.RunTLS(&tls.Config{Certificates: []tls.Certificate{cert}})
302+ Expect(err).ToNot(HaveOccurred())
303+ })
304+
305+ AfterEach(func() {
306+ mr.Close()
307+
308+ var err error
309+ mr, err = miniredis.Run()
310+ Expect(err).ToNot(HaveOccurred())
311+ })
312+
313+ tests.RunSessionStoreTests(
314+ func(opts *options.SessionOptions, cookieOpts *options.Cookie) (sessionsapi.SessionStore, error) {
315+ // Set the connection URL
316+ opts.Type = options.RedisSessionStoreType
317+ opts.Redis.ConnectionURL = "redis://127.0.0.1:" + mr.Port() // func (*Miniredis) StartTLS listens on 127.0.0.1
318+ opts.Redis.InsecureSkipTLSVerify = true
319+
320+ // Capture the session store so that we can close the client
321+ var err error
322+ ss, err = NewRedisSessionStore(opts, cookieOpts)
323+ return ss, err
324+ },
325+ func(d time.Duration) error {
326+ mr.FastForward(d)
327+ return nil
328+ },
329+ )
330+ })
227331})
pkg/util/util.go+43
@@ -1,9 +1,15 @@
11package util
22
33import (
4+ "crypto/rand"
5+ "crypto/rsa"
46 "crypto/x509"
7+ "crypto/x509/pkix"
58 "fmt"
69 "io/ioutil"
10+ "math/big"
11+ "net"
12+ "time"
713)
814
915func GetCertPool(paths []string) (*x509.CertPool, error) {
@@ -23,3 +29,40 @@ func GetCertPool(paths []string) (*x509.CertPool, error) {
2329 }
2430 return pool, nil
2531}
32+
33+// https://golang.org/src/crypto/tls/generate_cert.go as a function
34+func GenerateCert() ([]byte, []byte, error) {
35+ var err error
36+
37+ priv, err := rsa.GenerateKey(rand.Reader, 2048)
38+ if err != nil {
39+ return nil, nil, err
40+ }
41+
42+ keyBytes, err := x509.MarshalPKCS8PrivateKey(priv)
43+ if err != nil {
44+ return nil, keyBytes, err
45+ }
46+
47+ serialNumber, err := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128))
48+ if err != nil {
49+ return nil, keyBytes, err
50+ }
51+
52+ notBefore := time.Now()
53+ template := x509.Certificate{
54+ SerialNumber: serialNumber,
55+ Subject: pkix.Name{
56+ Organization: []string{"OAuth2 Proxy Test Suite"},
57+ },
58+ NotBefore: notBefore,
59+ NotAfter: notBefore.Add(time.Hour),
60+ KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment,
61+
62+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
63+
64+ IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
65+ }
66+ certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
67+ return certBytes, keyBytes, err
68+}
watcher.go+1
@@ -1,3 +1,4 @@
1+//go:build go1.3 && !plan9 && !solaris
12// +build go1.3,!plan9,!solaris
23
34package main
watcher_unsupported.go+1
@@ -1,3 +1,4 @@
1+//go:build !go1.3 || plan9 || solaris
12// +build !go1.3 plan9 solaris
23
34package main