mirror of https://github.com/jackc/pgx.git
Merge branch 'sean--stdlib-tls'
commit
1c32ce5945
85
conn.go
85
conn.go
|
@ -4,10 +4,12 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
@ -701,14 +703,23 @@ func ParseURI(uri string) (ConnConfig, error) {
|
||||||
cp.Dial = d.Dial
|
cp.Dial = d.Dial
|
||||||
}
|
}
|
||||||
|
|
||||||
err = configSSL(url.Query().Get("sslmode"), &cp)
|
tlsArgs := configTLSArgs{
|
||||||
|
sslCert: url.Query().Get("sslcert"),
|
||||||
|
sslKey: url.Query().Get("sslkey"),
|
||||||
|
sslMode: url.Query().Get("sslmode"),
|
||||||
|
sslRootCert: url.Query().Get("sslrootcert"),
|
||||||
|
}
|
||||||
|
err = configTLS(tlsArgs, &cp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cp, err
|
return cp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ignoreKeys := map[string]struct{}{
|
ignoreKeys := map[string]struct{}{
|
||||||
"sslmode": {},
|
|
||||||
"connect_timeout": {},
|
"connect_timeout": {},
|
||||||
|
"sslcert": {},
|
||||||
|
"sslkey": {},
|
||||||
|
"sslmode": {},
|
||||||
|
"sslrootcert": {},
|
||||||
}
|
}
|
||||||
|
|
||||||
cp.RuntimeParams = make(map[string]string)
|
cp.RuntimeParams = make(map[string]string)
|
||||||
|
@ -744,7 +755,7 @@ func ParseDSN(s string) (ConnConfig, error) {
|
||||||
|
|
||||||
m := dsnRegexp.FindAllStringSubmatch(s, -1)
|
m := dsnRegexp.FindAllStringSubmatch(s, -1)
|
||||||
|
|
||||||
var sslmode string
|
tlsArgs := configTLSArgs{}
|
||||||
|
|
||||||
cp.RuntimeParams = make(map[string]string)
|
cp.RuntimeParams = make(map[string]string)
|
||||||
|
|
||||||
|
@ -765,7 +776,13 @@ func ParseDSN(s string) (ConnConfig, error) {
|
||||||
case "dbname":
|
case "dbname":
|
||||||
cp.Database = b[2]
|
cp.Database = b[2]
|
||||||
case "sslmode":
|
case "sslmode":
|
||||||
sslmode = b[2]
|
tlsArgs.sslMode = b[2]
|
||||||
|
case "sslrootcert":
|
||||||
|
tlsArgs.sslRootCert = b[2]
|
||||||
|
case "sslcert":
|
||||||
|
tlsArgs.sslCert = b[2]
|
||||||
|
case "sslkey":
|
||||||
|
tlsArgs.sslKey = b[2]
|
||||||
case "connect_timeout":
|
case "connect_timeout":
|
||||||
timeout, err := strconv.ParseInt(b[2], 10, 64)
|
timeout, err := strconv.ParseInt(b[2], 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -779,7 +796,7 @@ func ParseDSN(s string) (ConnConfig, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := configSSL(sslmode, &cp)
|
err := configTLS(tlsArgs, &cp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cp, err
|
return cp, err
|
||||||
}
|
}
|
||||||
|
@ -859,7 +876,7 @@ func ParseEnvLibpq() (ConnConfig, error) {
|
||||||
|
|
||||||
sslmode := os.Getenv("PGSSLMODE")
|
sslmode := os.Getenv("PGSSLMODE")
|
||||||
|
|
||||||
err := configSSL(sslmode, &cc)
|
err := configTLS(configTLSArgs{sslMode: sslmode}, &cc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cc, err
|
return cc, err
|
||||||
}
|
}
|
||||||
|
@ -874,14 +891,27 @@ func ParseEnvLibpq() (ConnConfig, error) {
|
||||||
return cc, nil
|
return cc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configSSL(sslmode string, cc *ConnConfig) error {
|
type configTLSArgs struct {
|
||||||
// Match libpq default behavior
|
sslMode string
|
||||||
if sslmode == "" {
|
sslRootCert string
|
||||||
sslmode = "prefer"
|
sslCert string
|
||||||
|
sslKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
switch sslmode {
|
// configTLS uses lib/pq's TLS parameters to reconstruct a coherent tls.Config.
|
||||||
|
// Inputs are parsed out and provided by ParseDSN() or ParseURI().
|
||||||
|
func configTLS(args configTLSArgs, cc *ConnConfig) error {
|
||||||
|
// Match libpq default behavior
|
||||||
|
if args.sslMode == "" {
|
||||||
|
args.sslMode = "prefer"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch args.sslMode {
|
||||||
case "disable":
|
case "disable":
|
||||||
|
cc.UseFallbackTLS = false
|
||||||
|
cc.TLSConfig = nil
|
||||||
|
cc.FallbackTLSConfig = nil
|
||||||
|
return nil
|
||||||
case "allow":
|
case "allow":
|
||||||
cc.UseFallbackTLS = true
|
cc.UseFallbackTLS = true
|
||||||
cc.FallbackTLSConfig = &tls.Config{InsecureSkipVerify: true}
|
cc.FallbackTLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
@ -899,6 +929,39 @@ func configSSL(sslmode string, cc *ConnConfig) error {
|
||||||
return errors.New("sslmode is invalid")
|
return errors.New("sslmode is invalid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.sslRootCert != "" {
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
|
||||||
|
caPath := args.sslRootCert
|
||||||
|
caCert, err := ioutil.ReadFile(caPath)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "unable to read CA file %q", caPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||||
|
return errors.Wrap(err, "unable to add CA to cert pool")
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.TLSConfig.RootCAs = caCertPool
|
||||||
|
cc.TLSConfig.ClientCAs = caCertPool
|
||||||
|
}
|
||||||
|
|
||||||
|
sslcert := args.sslCert
|
||||||
|
sslkey := args.sslKey
|
||||||
|
|
||||||
|
if (sslcert != "" && sslkey == "") || (sslcert == "" && sslkey != "") {
|
||||||
|
return fmt.Errorf(`both "sslcert" and "sslkey" are required`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sslcert != "" && sslkey != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(sslcert, sslkey)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "unable to read cert")
|
||||||
|
}
|
||||||
|
|
||||||
|
cc.TLSConfig.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
package pgx_test
|
package pgx_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
// "crypto/tls"
|
||||||
|
// "crypto/x509"
|
||||||
|
// "fmt"
|
||||||
|
// "go/build"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "path"
|
||||||
|
|
||||||
"github.com/jackc/pgx"
|
"github.com/jackc/pgx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +29,51 @@ var cratedbConnConfig *pgx.ConnConfig = nil
|
||||||
// var md5ConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"}
|
// var md5ConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"}
|
||||||
// var plainPasswordConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_pw", Password: "secret", Database: "pgx_test"}
|
// var plainPasswordConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_pw", Password: "secret", Database: "pgx_test"}
|
||||||
// var invalidUserConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "invalid", Database: "pgx_test"}
|
// var invalidUserConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "invalid", Database: "pgx_test"}
|
||||||
// var tlsConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test", TLSConfig: &tls.Config{InsecureSkipVerify: true}}
|
|
||||||
// var customDialerConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"}
|
// var customDialerConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test"}
|
||||||
// var replicationConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_replication", Password: "secret", Database: "pgx_test"}
|
// var replicationConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_replication", Password: "secret", Database: "pgx_test"}
|
||||||
|
|
||||||
|
// var tlsConnConfig *pgx.ConnConfig = &pgx.ConnConfig{Host: "127.0.0.1", User: "pgx_md5", Password: "secret", Database: "pgx_test", TLSConfig: &tls.Config{InsecureSkipVerify: true}}
|
||||||
|
//
|
||||||
|
//// or to test client certs:
|
||||||
|
//
|
||||||
|
// var tlsConnConfig *pgx.ConnConfig
|
||||||
|
//
|
||||||
|
// func init() {
|
||||||
|
// homeDir := build.Default.GOPATH
|
||||||
|
// tlsConnConfig = &pgx.ConnConfig{
|
||||||
|
// Host: "127.0.0.1",
|
||||||
|
// User: "pgx_md5",
|
||||||
|
// Password: "secret",
|
||||||
|
// Database: "pgx_test",
|
||||||
|
// TLSConfig: &tls.Config{
|
||||||
|
// InsecureSkipVerify: true,
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
// caCertPool := x509.NewCertPool()
|
||||||
|
//
|
||||||
|
// caPath := path.Join(homeDir, "/src/github.com/jackc/pgx/rootCA.pem")
|
||||||
|
// caCert, err := ioutil.ReadFile(caPath)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Sprintf("unable to read CA file: %v", err))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||||
|
// panic("unable to add CA to cert pool")
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// tlsConnConfig.TLSConfig.RootCAs = caCertPool
|
||||||
|
// tlsConnConfig.TLSConfig.ClientCAs = caCertPool
|
||||||
|
//
|
||||||
|
// sslCert := path.Join(homeDir, "/src/github.com/jackc/pgx/pg_md5.crt")
|
||||||
|
// sslKey := path.Join(homeDir, "/src/github.com/jackc/pgx/pg_md5.key")
|
||||||
|
// if (sslCert != "" && sslKey == "") || (sslCert == "" && sslKey != "") {
|
||||||
|
// panic(`both "sslcert" and "sslkey" are required`)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// cert, err := tls.LoadX509KeyPair(sslCert, sslKey)
|
||||||
|
// if err != nil {
|
||||||
|
// panic(fmt.Sprintf("unable to read cert: %v", err))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// tlsConnConfig.TLSConfig.Certificates = []tls.Certificate{cert}
|
||||||
|
// }
|
||||||
|
|
|
@ -228,7 +228,8 @@ func TestConnectWithTLSFallback(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
connConfig.UseFallbackTLS = true
|
connConfig.UseFallbackTLS = true
|
||||||
connConfig.FallbackTLSConfig = &tls.Config{InsecureSkipVerify: true}
|
connConfig.FallbackTLSConfig = tlsConnConfig.TLSConfig
|
||||||
|
connConfig.FallbackTLSConfig.InsecureSkipVerify = true
|
||||||
|
|
||||||
conn, err = pgx.Connect(connConfig)
|
conn, err = pgx.Connect(connConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue