Contributing guide now includes instructions to test client ssl auth

pull/1364/head
Jack Christensen 2022-10-29 19:00:29 -05:00
parent 9eaeb51e30
commit 6b52e0b5e0
6 changed files with 85 additions and 14 deletions

View File

@ -41,7 +41,7 @@ This will run the vast majority of the tests, but some tests will be skipped (e.
### Creating a New PostgreSQL Cluster Exclusively for Testing
The following environment variables need to be set both for initial setup and whenever the tests are run. (direnv is
highly recommended):
highly recommended). Depending on your platform, you may need to change the host for `PGX_TEST_UNIX_SOCKET_CONN_STRING`.
```
export PGPORT=5015
@ -49,12 +49,13 @@ export PGUSER=postgres
export PGDATABASE=pgx_test
export POSTGRESQL_DATA_DIR=postgresql
export PGX_TEST_DATABASE="host=/private/tmp database=pgx_test"
export PGX_TEST_DATABASE="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
export PGX_TEST_UNIX_SOCKET_CONN_STRING="host=/private/tmp database=pgx_test"
export PGX_TEST_TCP_CONN_STRING="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
export PGX_TEST_MD5_PASSWORD_CONN_STRING="host=127.0.0.1 database=pgx_test user=pgx_md5 password=secret"
export PGX_TEST_PLAIN_PASSWORD_CONN_STRING=postgres://pgx_pw:secret@127.0.0.1/pgx_test
export PGX_TEST_TLS_CONN_STRING=postgres://pgx_ssl:secret@127.0.0.1/pgx_test?sslmode=require
export PGX_TEST_PLAIN_PASSWORD_CONN_STRING="host=127.0.0.1 user=pgx_pw password=secret"
export PGX_TEST_TLS_CONN_STRING="host=localhost user=pgx_ssl password=secret sslmode=verify-full sslrootcert=`pwd`/.testdb/ca.pem"
export PGX_TEST_TLS_CLIENT_CONN_STRING="host=127.0.0.1 user=pgx_sslcert sslmode=verify-full sslrootcert=`pwd`/.testdb/ca.pem database=pgx_test"
export PGX_TEST_SCRAM_PASSWORD_CONN_STRING="host=127.0.0.1 user=pgx_scram password=secret database=pgx_test"
```
@ -62,22 +63,25 @@ Create a new database cluster.
```
initdb --locale=en_US -E UTF-8 --username=postgres .testdb/$POSTGRESQL_DATA_DIR
echo "listen_addresses = '127.0.0.1'" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
echo "port = $PGPORT" >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
cat testsetup/postgresql_ssl.conf >> .testdb/$POSTGRESQL_DATA_DIR/postgresql.conf
cp testsetup/pg_hba.conf .testdb/$POSTGRESQL_DATA_DIR/pg_hba.conf
cp testsetup/ca.cnf .testdb
cp testsetup/localhost.cnf .testdb
cp testsetup/pgx_sslcert.cnf .testdb
cd .testdb
# Generate a CA public / private key pair.
openssl genrsa -out ca.key 4096
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -subj '/O=pgx-test-root' -out ca.pem
openssl req -x509 -config ca.cnf -new -nodes -key ca.key -sha256 -days 365 -subj '/O=pgx-test-root' -out ca.pem
# Generate the certificate for localhost (the server).
openssl genrsa -out localhost.key 2048
openssl req -new -config localhost.cnf -key localhost.key -out localhost.csr
openssl x509 -req -in localhost.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out localhost.crt -days 3650 -sha256 -extfile localhost.cnf -extensions v3_req
openssl x509 -req -in localhost.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out localhost.crt -days 364 -sha256 -extfile localhost.cnf -extensions v3_req
# Copy certificates to server directory and set permissions.
cp ca.pem $POSTGRESQL_DATA_DIR/root.crt
@ -85,6 +89,11 @@ cp localhost.key $POSTGRESQL_DATA_DIR/server.key
chmod 600 $POSTGRESQL_DATA_DIR/server.key
cp localhost.crt $POSTGRESQL_DATA_DIR/server.crt
# Generate the certificate for client authentication.
openssl genrsa -des -out pgx_sslcert.key -passout pass:certpw 2048
openssl req -new -config pgx_sslcert.cnf -key pgx_sslcert.key -passin pass:certpw -out pgx_sslcert.csr
openssl x509 -req -in pgx_sslcert.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out pgx_sslcert.crt -days 363 -sha256 -extfile pgx_sslcert.cnf -extensions v3_req
cd ..
```

View File

@ -93,15 +93,60 @@ func TestConnectTLS(t *testing.T) {
t.Skipf("Skipping due to missing environment variable %v", "PGX_TEST_TLS_CONN_STRING")
}
var conn *pgconn.PgConn
var err error
conn, err := pgconn.Connect(context.Background(), connString)
require.NoError(t, err)
result := conn.ExecParams(context.Background(), `select ssl from pg_stat_ssl where pg_backend_pid() = pid;`, nil, nil, nil, nil).Read()
require.NoError(t, result.Err)
require.Len(t, result.Rows, 1)
require.Len(t, result.Rows[0], 1)
require.Equalf(t, "t", string(result.Rows[0][0]), "not a TLS connection")
closeConn(t, conn)
}
func TestConnectTLSPasswordProtectedClientCertWithSSLPassword(t *testing.T) {
t.Parallel()
connString := os.Getenv("PGX_TEST_TLS_CLIENT_CONN_STRING")
if connString == "" {
t.Skipf("Skipping due to missing environment variable %v", "PGX_TEST_TLS_CLIENT_CONN_STRING")
}
if os.Getenv("PGX_SSL_PASSWORD") == "" {
t.Skipf("Skipping due to missing environment variable %v", "PGX_SSL_PASSWORD")
}
connString += " sslpassword=" + os.Getenv("PGX_SSL_PASSWORD")
conn, err := pgconn.Connect(context.Background(), connString)
require.NoError(t, err)
result := conn.ExecParams(context.Background(), `select ssl from pg_stat_ssl where pg_backend_pid() = pid;`, nil, nil, nil, nil).Read()
require.NoError(t, result.Err)
require.Len(t, result.Rows, 1)
require.Len(t, result.Rows[0], 1)
require.Equalf(t, "t", string(result.Rows[0][0]), "not a TLS connection")
closeConn(t, conn)
}
func TestConnectTLSPasswordProtectedClientCertWithGetSSLPasswordConfigOption(t *testing.T) {
t.Parallel()
connString := os.Getenv("PGX_TEST_TLS_CLIENT_CONN_STRING")
if connString == "" {
t.Skipf("Skipping due to missing environment variable %v", "PGX_TEST_TLS_CLIENT_CONN_STRING")
}
if os.Getenv("PGX_SSL_PASSWORD") == "" {
t.Skipf("Skipping due to missing environment variable %v", "PGX_SSL_PASSWORD")
}
var sslOptions pgconn.ParseConfigOptions
sslOptions.GetSSLPassword = GetSSLPassword
config, err := pgconn.ParseConfigWithOptions(connString, sslOptions)
require.Nil(t, err)
conn, err = pgconn.ConnectConfig(context.Background(), config)
conn, err := pgconn.ConnectConfig(context.Background(), config)
require.NoError(t, err)
result := conn.ExecParams(context.Background(), `select ssl from pg_stat_ssl where pg_backend_pid() = pid;`, nil, nil, nil, nil).Read()

6
testsetup/ca.cnf Normal file
View File

@ -0,0 +1,6 @@
[ req ]
distinguished_name = dn
[ dn ]
commonName = ca
[ ext ]
basicConstraints =CA:TRUE,pathlen:0

View File

@ -4,3 +4,4 @@ host all pgx_md5 127.0.0.1/32 md5
host all pgx_scram 127.0.0.1/32 scram-sha-256
host all pgx_pw 127.0.0.1/32 password
hostssl all pgx_ssl 127.0.0.1/32 scram-sha-256
hostssl all pgx_sslcert 127.0.0.1/32 cert

View File

@ -0,0 +1,9 @@
[ req ]
default_bits = 2048
distinguished_name = dn
req_extensions = v3_req
prompt = no
[ dn ]
commonName = pgx_sslcert
[ v3_req ]
keyUsage = digitalSignature

View File

@ -3,12 +3,13 @@ create extension hstore;
create domain uint64 as numeric(20,0);
-- Create users for different types of connections and authentication.
create user pgx_ssl PASSWORD 'secret' with superuser;
create user pgx_ssl with superuser PASSWORD 'secret';
create user pgx_sslcert with superuser PASSWORD 'secret';
set password_encryption = md5;
create user pgx_md5 PASSWORD 'secret' with superuser;
create user pgx_md5 with superuser PASSWORD 'secret';
set password_encryption = 'scram-sha-256';
create user pgx_pw PASSWORD 'secret' with superuser;
create user pgx_scram PASSWORD 'secret' with superuser;
create user pgx_pw with superuser PASSWORD 'secret';
create user pgx_scram with superuser PASSWORD 'secret';
\set whoami `whoami`
create user :whoami with superuser; -- unix domain socket user