Commit 0d1a3343 authored by Michael Paquier's avatar Michael Paquier

Move some client-specific routines from SSLServer to PostgresNode

test_connect_ok() and test_connect_fails() have always been part of the
SSL tests, and check if a connection to the backend should work or not,
and there are sanity checks done on specific error patterns dropped by
libpq if the connection fails.

This was fundamentally wrong on two aspects.  First, SSLServer.pm works
mostly on setting up and changing the SSL configuration of a
PostgresNode, and has really nothing to do with the client.  Second,
the situation became worse in light of b34ca595, where the SSL tests
would finish by using a psql command that may not come from the same
installation as the node set up.

This commit moves those client routines into PostgresNode, making easier
the refactoring of SSLServer to become more SSL-implementation aware.
This can also be reused by the ldap, kerberos and authentication test
suites for connection checks, and a follow-up patch should extend those
interfaces to match with backend log patterns.

Author: Michael Paquier
Reviewed-by: Andrew Dunstan, Daniel Gustafsson, Álvaro Herrera
Discussion: https://postgr.es/m/YGLKNBf9zyh6+WSt@paquier.xyz
parent 28b3e390
...@@ -1511,6 +1511,11 @@ the B<timed_out> parameter is also given. ...@@ -1511,6 +1511,11 @@ the B<timed_out> parameter is also given.
If B<timeout> is set and this parameter is given, the scalar it references If B<timeout> is set and this parameter is given, the scalar it references
is set to true if the psql call times out. is set to true if the psql call times out.
=item connstr => B<value>
If set, use this as the connection string for the connection to the
backend.
=item replication => B<value> =item replication => B<value>
If set, add B<replication=value> to the conninfo string. If set, add B<replication=value> to the conninfo string.
...@@ -1550,14 +1555,20 @@ sub psql ...@@ -1550,14 +1555,20 @@ sub psql
my $replication = $params{replication}; my $replication = $params{replication};
my $timeout = undef; my $timeout = undef;
my $timeout_exception = 'psql timed out'; my $timeout_exception = 'psql timed out';
my @psql_params = (
'psql', # Build the connection string.
'-XAtq', my $psql_connstr;
'-d', if (defined $params{connstr})
$self->connstr($dbname) {
. (defined $replication ? " replication=$replication" : ""), $psql_connstr = $params{connstr};
'-f', }
'-'); else
{
$psql_connstr = $self->connstr($dbname);
}
$psql_connstr .= defined $replication ? " replication=$replication" : "";
my @psql_params = ('psql', '-XAtq', '-d', $psql_connstr, '-f', '-');
# If the caller wants an array and hasn't passed stdout/stderr # If the caller wants an array and hasn't passed stdout/stderr
# references, allocate temporary ones to capture them so we # references, allocate temporary ones to capture them so we
...@@ -1849,6 +1860,51 @@ sub interactive_psql ...@@ -1849,6 +1860,51 @@ sub interactive_psql
=pod =pod
=item $node->connect_ok($connstr, $test_name)
Attempt a connection with a custom connection string. This is expected
to succeed.
=cut
sub connect_ok
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ($self, $connstr, $test_name) = @_;
my ($ret, $stdout, $stderr) = $self->psql(
'postgres',
"SELECT \$\$connected with $connstr\$\$",
connstr => "$connstr",
on_error_stop => 0);
ok($ret == 0, $test_name);
}
=pod
=item $node->connect_fails($connstr, $expected_stderr, $test_name)
Attempt a connection with a custom connection string. This is expected
to fail with a message that matches the regular expression
$expected_stderr.
=cut
sub connect_fails
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ($self, $connstr, $expected_stderr, $test_name) = @_;
my ($ret, $stdout, $stderr) = $self->psql(
'postgres',
"SELECT \$\$connected with $connstr\$\$",
connstr => "$connstr");
ok($ret != 0, $test_name);
like($stderr, $expected_stderr, "$test_name: matches");
}
=pod
=item $node->poll_query_until($dbname, $query [, $expected ]) =item $node->poll_query_until($dbname, $query [, $expected ])
Run B<$query> repeatedly, until it returns the B<$expected> result Run B<$query> repeatedly, until it returns the B<$expected> result
......
...@@ -135,103 +135,94 @@ $common_connstr = ...@@ -135,103 +135,94 @@ $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test"; "user=ssltestuser dbname=trustdb sslcert=invalid hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
# The server should not accept non-SSL connections. # The server should not accept non-SSL connections.
test_connect_fails( $node->connect_fails(
$common_connstr, "sslmode=disable", "$common_connstr sslmode=disable",
qr/\Qno pg_hba.conf entry\E/, qr/\Qno pg_hba.conf entry\E/,
"server doesn't accept non-SSL connections"); "server doesn't accept non-SSL connections");
# Try without a root cert. In sslmode=require, this should work. In verify-ca # Try without a root cert. In sslmode=require, this should work. In verify-ca
# or verify-full mode it should fail. # or verify-full mode it should fail.
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=invalid sslmode=require",
"sslrootcert=invalid sslmode=require",
"connect without server root cert sslmode=require"); "connect without server root cert sslmode=require");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=invalid sslmode=verify-ca",
"sslrootcert=invalid sslmode=verify-ca",
qr/root certificate file "invalid" does not exist/, qr/root certificate file "invalid" does not exist/,
"connect without server root cert sslmode=verify-ca"); "connect without server root cert sslmode=verify-ca");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=invalid sslmode=verify-full",
"sslrootcert=invalid sslmode=verify-full",
qr/root certificate file "invalid" does not exist/, qr/root certificate file "invalid" does not exist/,
"connect without server root cert sslmode=verify-full"); "connect without server root cert sslmode=verify-full");
# Try with wrong root cert, should fail. (We're using the client CA as the # Try with wrong root cert, should fail. (We're using the client CA as the
# root, but the server's key is signed by the server CA.) # root, but the server's key is signed by the server CA.)
test_connect_fails($common_connstr, $node->connect_fails(
"sslrootcert=ssl/client_ca.crt sslmode=require", "$common_connstr sslrootcert=ssl/client_ca.crt sslmode=require",
qr/SSL error/, "connect with wrong server root cert sslmode=require"); qr/SSL error/,
test_connect_fails($common_connstr, "connect with wrong server root cert sslmode=require");
"sslrootcert=ssl/client_ca.crt sslmode=verify-ca", $node->connect_fails(
qr/SSL error/, "connect with wrong server root cert sslmode=verify-ca"); "$common_connstr sslrootcert=ssl/client_ca.crt sslmode=verify-ca",
test_connect_fails($common_connstr, qr/SSL error/,
"sslrootcert=ssl/client_ca.crt sslmode=verify-full", "connect with wrong server root cert sslmode=verify-ca");
qr/SSL error/, "connect with wrong server root cert sslmode=verify-full"); $node->connect_fails(
"$common_connstr sslrootcert=ssl/client_ca.crt sslmode=verify-full",
qr/SSL error/,
"connect with wrong server root cert sslmode=verify-full");
# Try with just the server CA's cert. This fails because the root file # Try with just the server CA's cert. This fails because the root file
# must contain the whole chain up to the root CA. # must contain the whole chain up to the root CA.
test_connect_fails($common_connstr, $node->connect_fails(
"sslrootcert=ssl/server_ca.crt sslmode=verify-ca", "$common_connstr sslrootcert=ssl/server_ca.crt sslmode=verify-ca",
qr/SSL error/, "connect with server CA cert, without root CA"); qr/SSL error/,
"connect with server CA cert, without root CA");
# And finally, with the correct root cert. # And finally, with the correct root cert.
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require",
"sslrootcert=ssl/root+server_ca.crt sslmode=require",
"connect with correct server CA cert file sslmode=require"); "connect with correct server CA cert file sslmode=require");
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
"connect with correct server CA cert file sslmode=verify-ca"); "connect with correct server CA cert file sslmode=verify-ca");
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-full",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-full",
"connect with correct server CA cert file sslmode=verify-full"); "connect with correct server CA cert file sslmode=verify-full");
# Test with cert root file that contains two certificates. The client should # Test with cert root file that contains two certificates. The client should
# be able to pick the right one, regardless of the order in the file. # be able to pick the right one, regardless of the order in the file.
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/both-cas-1.crt sslmode=verify-ca",
"sslrootcert=ssl/both-cas-1.crt sslmode=verify-ca",
"cert root file that contains two certificates, order 1"); "cert root file that contains two certificates, order 1");
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/both-cas-2.crt sslmode=verify-ca",
"sslrootcert=ssl/both-cas-2.crt sslmode=verify-ca",
"cert root file that contains two certificates, order 2"); "cert root file that contains two certificates, order 2");
# CRL tests # CRL tests
# Invalid CRL filename is the same as no CRL, succeeds # Invalid CRL filename is the same as no CRL, succeeds
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=invalid",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=invalid",
"sslcrl option with invalid file name"); "sslcrl option with invalid file name");
# A CRL belonging to a different CA is not accepted, fails # A CRL belonging to a different CA is not accepted, fails
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/client.crl",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/client.crl",
qr/SSL error/, qr/SSL error/,
"CRL belonging to a different CA"); "CRL belonging to a different CA");
# The same for CRL directory # The same for CRL directory
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/client-crldir",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/client-crldir",
qr/SSL error/, qr/SSL error/,
"directory CRL belonging to a different CA"); "directory CRL belonging to a different CA");
# With the correct CRL, succeeds (this cert is not revoked) # With the correct CRL, succeeds (this cert is not revoked)
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
"CRL with a non-revoked cert"); "CRL with a non-revoked cert");
# The same for CRL directory # The same for CRL directory
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
"directory CRL with a non-revoked cert"); "directory CRL with a non-revoked cert");
# Check that connecting with verify-full fails, when the hostname doesn't # Check that connecting with verify-full fails, when the hostname doesn't
...@@ -239,17 +230,13 @@ test_connect_ok( ...@@ -239,17 +230,13 @@ test_connect_ok(
$common_connstr = $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR"; "user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR";
test_connect_ok( $node->connect_ok("$common_connstr sslmode=require host=wronghost.test",
$common_connstr,
"sslmode=require host=wronghost.test",
"mismatch between host name and server certificate sslmode=require"); "mismatch between host name and server certificate sslmode=require");
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslmode=verify-ca host=wronghost.test",
"sslmode=verify-ca host=wronghost.test",
"mismatch between host name and server certificate sslmode=verify-ca"); "mismatch between host name and server certificate sslmode=verify-ca");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslmode=verify-full host=wronghost.test",
"sslmode=verify-full host=wronghost.test",
qr/\Qserver certificate for "common-name.pg-ssltest.test" does not match host name "wronghost.test"\E/, qr/\Qserver certificate for "common-name.pg-ssltest.test" does not match host name "wronghost.test"\E/,
"mismatch between host name and server certificate sslmode=verify-full"); "mismatch between host name and server certificate sslmode=verify-full");
...@@ -259,27 +246,21 @@ switch_server_cert($node, 'server-multiple-alt-names'); ...@@ -259,27 +246,21 @@ switch_server_cert($node, 'server-multiple-alt-names');
$common_connstr = $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full"; "user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr host=dns1.alt-name.pg-ssltest.test",
"host=dns1.alt-name.pg-ssltest.test",
"host name matching with X.509 Subject Alternative Names 1"); "host name matching with X.509 Subject Alternative Names 1");
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr host=dns2.alt-name.pg-ssltest.test",
"host=dns2.alt-name.pg-ssltest.test",
"host name matching with X.509 Subject Alternative Names 2"); "host name matching with X.509 Subject Alternative Names 2");
test_connect_ok( $node->connect_ok("$common_connstr host=foo.wildcard.pg-ssltest.test",
$common_connstr,
"host=foo.wildcard.pg-ssltest.test",
"host name matching with X.509 Subject Alternative Names wildcard"); "host name matching with X.509 Subject Alternative Names wildcard");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr host=wronghost.alt-name.pg-ssltest.test",
"host=wronghost.alt-name.pg-ssltest.test",
qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "wronghost.alt-name.pg-ssltest.test"\E/, qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "wronghost.alt-name.pg-ssltest.test"\E/,
"host name not matching with X.509 Subject Alternative Names"); "host name not matching with X.509 Subject Alternative Names");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr host=deep.subdomain.wildcard.pg-ssltest.test",
"host=deep.subdomain.wildcard.pg-ssltest.test",
qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/, qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 2 other names) does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/,
"host name not matching with X.509 Subject Alternative Names wildcard"); "host name not matching with X.509 Subject Alternative Names wildcard");
...@@ -290,19 +271,16 @@ switch_server_cert($node, 'server-single-alt-name'); ...@@ -290,19 +271,16 @@ switch_server_cert($node, 'server-single-alt-name');
$common_connstr = $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full"; "user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr host=single.alt-name.pg-ssltest.test",
"host=single.alt-name.pg-ssltest.test",
"host name matching with a single X.509 Subject Alternative Name"); "host name matching with a single X.509 Subject Alternative Name");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr host=wronghost.alt-name.pg-ssltest.test",
"host=wronghost.alt-name.pg-ssltest.test",
qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "wronghost.alt-name.pg-ssltest.test"\E/, qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "wronghost.alt-name.pg-ssltest.test"\E/,
"host name not matching with a single X.509 Subject Alternative Name"); "host name not matching with a single X.509 Subject Alternative Name");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr host=deep.subdomain.wildcard.pg-ssltest.test",
"host=deep.subdomain.wildcard.pg-ssltest.test",
qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/, qr/\Qserver certificate for "single.alt-name.pg-ssltest.test" does not match host name "deep.subdomain.wildcard.pg-ssltest.test"\E/,
"host name not matching with a single X.509 Subject Alternative Name wildcard" "host name not matching with a single X.509 Subject Alternative Name wildcard"
); );
...@@ -314,17 +292,12 @@ switch_server_cert($node, 'server-cn-and-alt-names'); ...@@ -314,17 +292,12 @@ switch_server_cert($node, 'server-cn-and-alt-names');
$common_connstr = $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full"; "user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR sslmode=verify-full";
test_connect_ok( $node->connect_ok("$common_connstr host=dns1.alt-name.pg-ssltest.test",
$common_connstr,
"host=dns1.alt-name.pg-ssltest.test",
"certificate with both a CN and SANs 1"); "certificate with both a CN and SANs 1");
test_connect_ok( $node->connect_ok("$common_connstr host=dns2.alt-name.pg-ssltest.test",
$common_connstr,
"host=dns2.alt-name.pg-ssltest.test",
"certificate with both a CN and SANs 2"); "certificate with both a CN and SANs 2");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr host=common-name.pg-ssltest.test",
"host=common-name.pg-ssltest.test",
qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 1 other name) does not match host name "common-name.pg-ssltest.test"\E/, qr/\Qserver certificate for "dns1.alt-name.pg-ssltest.test" (and 1 other name) does not match host name "common-name.pg-ssltest.test"\E/,
"certificate with both a CN and SANs ignores CN"); "certificate with both a CN and SANs ignores CN");
...@@ -334,13 +307,12 @@ switch_server_cert($node, 'server-no-names'); ...@@ -334,13 +307,12 @@ switch_server_cert($node, 'server-no-names');
$common_connstr = $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR"; "user=ssltestuser dbname=trustdb sslcert=invalid sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR";
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslmode=verify-ca host=common-name.pg-ssltest.test",
"sslmode=verify-ca host=common-name.pg-ssltest.test",
"server certificate without CN or SANs sslmode=verify-ca"); "server certificate without CN or SANs sslmode=verify-ca");
test_connect_fails( $node->connect_fails(
$common_connstr, $common_connstr . " "
"sslmode=verify-full host=common-name.pg-ssltest.test", . "sslmode=verify-full host=common-name.pg-ssltest.test",
qr/could not get server's host name from server certificate/, qr/could not get server's host name from server certificate/,
"server certificate without CN or SANs sslmode=verify-full"); "server certificate without CN or SANs sslmode=verify-full");
...@@ -351,18 +323,15 @@ $common_connstr = ...@@ -351,18 +323,15 @@ $common_connstr =
"user=ssltestuser dbname=trustdb sslcert=invalid hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test"; "user=ssltestuser dbname=trustdb sslcert=invalid hostaddr=$SERVERHOSTADDR host=common-name.pg-ssltest.test";
# Without the CRL, succeeds. With it, fails. # Without the CRL, succeeds. With it, fails.
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca",
"connects without client-side CRL"); "connects without client-side CRL");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrl=ssl/root+server.crl",
qr/SSL error/, qr/SSL error/,
"does not connect with client-side CRL file"); "does not connect with client-side CRL file");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
"sslrootcert=ssl/root+server_ca.crt sslmode=verify-ca sslcrldir=ssl/root+server-crldir",
qr/SSL error/, qr/SSL error/,
"does not connect with client-side CRL directory"); "does not connect with client-side CRL directory");
...@@ -381,23 +350,19 @@ command_like( ...@@ -381,23 +350,19 @@ command_like(
'pg_stat_ssl view without client certificate'); 'pg_stat_ssl view without client certificate');
# Test min/max SSL protocol versions. # Test min/max SSL protocol versions.
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.2",
"sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.2",
"connection success with correct range of TLS protocol versions"); "connection success with correct range of TLS protocol versions");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.1",
"sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=TLSv1.2 ssl_max_protocol_version=TLSv1.1",
qr/invalid SSL protocol version range/, qr/invalid SSL protocol version range/,
"connection failure with incorrect range of TLS protocol versions"); "connection failure with incorrect range of TLS protocol versions");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=incorrect_tls",
"sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_min_protocol_version=incorrect_tls",
qr/invalid ssl_min_protocol_version value/, qr/invalid ssl_min_protocol_version value/,
"connection failure with an incorrect SSL protocol minimum bound"); "connection failure with an incorrect SSL protocol minimum bound");
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_max_protocol_version=incorrect_tls",
"sslrootcert=ssl/root+server_ca.crt sslmode=require ssl_max_protocol_version=incorrect_tls",
qr/invalid ssl_max_protocol_version value/, qr/invalid ssl_max_protocol_version value/,
"connection failure with an incorrect SSL protocol maximum bound"); "connection failure with an incorrect SSL protocol maximum bound");
...@@ -411,44 +376,38 @@ $common_connstr = ...@@ -411,44 +376,38 @@ $common_connstr =
"sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR"; "sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=certdb hostaddr=$SERVERHOSTADDR";
# no client cert # no client cert
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=invalid",
"user=ssltestuser sslcert=invalid",
qr/connection requires a valid client certificate/, qr/connection requires a valid client certificate/,
"certificate authorization fails without client cert"); "certificate authorization fails without client cert");
# correct client cert in unencrypted PEM # correct client cert in unencrypted PEM
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"certificate authorization succeeds with correct client cert in PEM format" "certificate authorization succeeds with correct client cert in PEM format"
); );
# correct client cert in unencrypted DER # correct client cert in unencrypted DER
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-der_tmp.key",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-der_tmp.key",
"certificate authorization succeeds with correct client cert in DER format" "certificate authorization succeeds with correct client cert in DER format"
); );
# correct client cert in encrypted PEM # correct client cert in encrypted PEM
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword='dUmmyP^#+'",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword='dUmmyP^#+'",
"certificate authorization succeeds with correct client cert in encrypted PEM format" "certificate authorization succeeds with correct client cert in encrypted PEM format"
); );
# correct client cert in encrypted DER # correct client cert in encrypted DER
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-der_tmp.key sslpassword='dUmmyP^#+'",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-der_tmp.key sslpassword='dUmmyP^#+'",
"certificate authorization succeeds with correct client cert in encrypted DER format" "certificate authorization succeeds with correct client cert in encrypted DER format"
); );
# correct client cert in encrypted PEM with wrong password # correct client cert in encrypted PEM with wrong password
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword='wrong'",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword='wrong'",
qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": bad decrypt\E!, qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": bad decrypt\E!,
"certificate authorization fails with correct client cert and wrong password in encrypted PEM format" "certificate authorization fails with correct client cert and wrong password in encrypted PEM format"
); );
...@@ -457,29 +416,23 @@ test_connect_fails( ...@@ -457,29 +416,23 @@ test_connect_fails(
# correct client cert using whole DN # correct client cert using whole DN
my $dn_connstr = "$common_connstr dbname=certdb_dn"; my $dn_connstr = "$common_connstr dbname=certdb_dn";
test_connect_ok( $node->connect_ok(
$dn_connstr, "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key",
"user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key", "certificate authorization succeeds with DN mapping");
"certificate authorization succeeds with DN mapping"
);
# same thing but with a regex # same thing but with a regex
$dn_connstr = "$common_connstr dbname=certdb_dn_re"; $dn_connstr = "$common_connstr dbname=certdb_dn_re";
test_connect_ok( $node->connect_ok(
$dn_connstr, "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key",
"user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key", "certificate authorization succeeds with DN regex mapping");
"certificate authorization succeeds with DN regex mapping"
);
# same thing but using explicit CN # same thing but using explicit CN
$dn_connstr = "$common_connstr dbname=certdb_cn"; $dn_connstr = "$common_connstr dbname=certdb_cn";
test_connect_ok( $node->connect_ok(
$dn_connstr, "$dn_connstr user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key",
"user=ssltestuser sslcert=ssl/client-dn.crt sslkey=ssl/client-dn_tmp.key", "certificate authorization succeeds with CN mapping");
"certificate authorization succeeds with CN mapping"
);
...@@ -491,17 +444,15 @@ TODO: ...@@ -491,17 +444,15 @@ TODO:
todo_skip "Need Pty support", 4; todo_skip "Need Pty support", 4;
# correct client cert in encrypted PEM with empty password # correct client cert in encrypted PEM with empty password
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword=''",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key sslpassword=''",
qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": processing error\E!, qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": processing error\E!,
"certificate authorization fails with correct client cert and empty password in encrypted PEM format" "certificate authorization fails with correct client cert and empty password in encrypted PEM format"
); );
# correct client cert in encrypted PEM with no password # correct client cert in encrypted PEM with no password
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client-encrypted-pem_tmp.key",
qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": processing error\E!, qr!\Qprivate key file "ssl/client-encrypted-pem_tmp.key": processing error\E!,
"certificate authorization fails with correct client cert and no password in encrypted PEM format" "certificate authorization fails with correct client cert and no password in encrypted PEM format"
); );
...@@ -532,25 +483,22 @@ SKIP: ...@@ -532,25 +483,22 @@ SKIP:
{ {
skip "Permissions check not enforced on Windows", 2 if ($windows_os); skip "Permissions check not enforced on Windows", 2 if ($windows_os);
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_wrongperms_tmp.key",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_wrongperms_tmp.key",
qr!\Qprivate key file "ssl/client_wrongperms_tmp.key" has group or world access\E!, qr!\Qprivate key file "ssl/client_wrongperms_tmp.key" has group or world access\E!,
"certificate authorization fails because of file permissions"); "certificate authorization fails because of file permissions");
} }
# client cert belonging to another user # client cert belonging to another user
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
qr/certificate authentication failed for user "anotheruser"/, qr/certificate authentication failed for user "anotheruser"/,
"certificate authorization fails with client cert belonging to another user" "certificate authorization fails with client cert belonging to another user"
); );
# revoked client cert # revoked client cert
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
"user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
qr/SSL error/, qr/SSL error/,
"certificate authorization fails with revoked client cert"); "certificate authorization fails with revoked client cert");
...@@ -560,24 +508,21 @@ test_connect_fails( ...@@ -560,24 +508,21 @@ test_connect_fails(
$common_connstr = $common_connstr =
"sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=verifydb hostaddr=$SERVERHOSTADDR"; "sslrootcert=ssl/root+server_ca.crt sslmode=require dbname=verifydb hostaddr=$SERVERHOSTADDR";
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"user=ssltestuser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"auth_option clientcert=verify-full succeeds with matching username and Common Name" "auth_option clientcert=verify-full succeeds with matching username and Common Name"
); );
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
qr/FATAL/, qr/FATAL/,
"auth_option clientcert=verify-full fails with mismatching username and Common Name" "auth_option clientcert=verify-full fails with mismatching username and Common Name"
); );
# Check that connecting with auth-optionverify-ca in pg_hba : # Check that connecting with auth-optionverify-ca in pg_hba :
# works, when username doesn't match Common Name # works, when username doesn't match Common Name
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=yetanotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"user=yetanotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"auth_option clientcert=verify-ca succeeds with mismatching username and Common Name" "auth_option clientcert=verify-ca succeeds with mismatching username and Common Name"
); );
...@@ -586,20 +531,19 @@ switch_server_cert($node, 'server-cn-only', 'root_ca'); ...@@ -586,20 +531,19 @@ switch_server_cert($node, 'server-cn-only', 'root_ca');
$common_connstr = $common_connstr =
"user=ssltestuser dbname=certdb sslkey=ssl/client_tmp.key sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR"; "user=ssltestuser dbname=certdb sslkey=ssl/client_tmp.key sslrootcert=ssl/root+server_ca.crt hostaddr=$SERVERHOSTADDR";
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr sslmode=require sslcert=ssl/client+client_ca.crt",
"sslmode=require sslcert=ssl/client+client_ca.crt",
"intermediate client certificate is provided by client"); "intermediate client certificate is provided by client");
test_connect_fails($common_connstr, "sslmode=require sslcert=ssl/client.crt", $node->connect_fails(
$common_connstr . " " . "sslmode=require sslcert=ssl/client.crt",
qr/SSL error/, "intermediate client certificate is missing"); qr/SSL error/, "intermediate client certificate is missing");
# test server-side CRL directory # test server-side CRL directory
switch_server_cert($node, 'server-cn-only', undef, undef, 'root+client-crldir'); switch_server_cert($node, 'server-cn-only', undef, undef, 'root+client-crldir');
# revoked client cert # revoked client cert
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
"user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
qr/SSL error/, qr/SSL error/,
"certificate authorization fails with revoked client cert with server-side CRL directory"); "certificate authorization fails with revoked client cert with server-side CRL directory");
......
...@@ -53,39 +53,34 @@ $common_connstr = ...@@ -53,39 +53,34 @@ $common_connstr =
"dbname=trustdb sslmode=require sslcert=invalid sslrootcert=invalid hostaddr=$SERVERHOSTADDR"; "dbname=trustdb sslmode=require sslcert=invalid sslrootcert=invalid hostaddr=$SERVERHOSTADDR";
# Default settings # Default settings
test_connect_ok($common_connstr, "user=ssltestuser", $node->connect_ok(
"$common_connstr user=ssltestuser",
"Basic SCRAM authentication with SSL"); "Basic SCRAM authentication with SSL");
# Test channel_binding # Test channel_binding
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser channel_binding=invalid_value",
"user=ssltestuser channel_binding=invalid_value",
qr/invalid channel_binding value: "invalid_value"/, qr/invalid channel_binding value: "invalid_value"/,
"SCRAM with SSL and channel_binding=invalid_value"); "SCRAM with SSL and channel_binding=invalid_value");
test_connect_ok( $node->connect_ok("$common_connstr user=ssltestuser channel_binding=disable",
$common_connstr,
"user=ssltestuser channel_binding=disable",
"SCRAM with SSL and channel_binding=disable"); "SCRAM with SSL and channel_binding=disable");
if ($supports_tls_server_end_point) if ($supports_tls_server_end_point)
{ {
test_connect_ok( $node->connect_ok(
$common_connstr, "$common_connstr user=ssltestuser channel_binding=require",
"user=ssltestuser channel_binding=require",
"SCRAM with SSL and channel_binding=require"); "SCRAM with SSL and channel_binding=require");
} }
else else
{ {
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=ssltestuser channel_binding=require",
"user=ssltestuser channel_binding=require",
qr/channel binding is required, but server did not offer an authentication method that supports channel binding/, qr/channel binding is required, but server did not offer an authentication method that supports channel binding/,
"SCRAM with SSL and channel_binding=require"); "SCRAM with SSL and channel_binding=require");
} }
# Now test when the user has an MD5-encrypted password; should fail # Now test when the user has an MD5-encrypted password; should fail
test_connect_fails( $node->connect_fails(
$common_connstr, "$common_connstr user=md5testuser channel_binding=require",
"user=md5testuser channel_binding=require",
qr/channel binding required but not supported by server's authentication request/, qr/channel binding required but not supported by server's authentication request/,
"MD5 with SSL and channel_binding=require"); "MD5 with SSL and channel_binding=require");
...@@ -96,9 +91,8 @@ test_connect_fails( ...@@ -96,9 +91,8 @@ test_connect_fails(
my $client_tmp_key = "ssl/client_scram_tmp.key"; my $client_tmp_key = "ssl/client_scram_tmp.key";
copy("ssl/client.key", $client_tmp_key); copy("ssl/client.key", $client_tmp_key);
chmod 0600, $client_tmp_key; chmod 0600, $client_tmp_key;
test_connect_fails( $node->connect_fails(
"sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR", "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR dbname=certdb user=ssltestuser channel_binding=require",
"dbname=certdb user=ssltestuser channel_binding=require",
qr/channel binding required, but server authenticated client without channel binding/, qr/channel binding required, but server authenticated client without channel binding/,
"Cert authentication and channel_binding=require"); "Cert authentication and channel_binding=require");
......
...@@ -37,46 +37,8 @@ use Exporter 'import'; ...@@ -37,46 +37,8 @@ use Exporter 'import';
our @EXPORT = qw( our @EXPORT = qw(
configure_test_server_for_ssl configure_test_server_for_ssl
switch_server_cert switch_server_cert
test_connect_fails
test_connect_ok
); );
# Define a couple of helper functions to test connecting to the server.
# The first argument is a base connection string to use for connection.
# The second argument is a complementary connection string.
sub test_connect_ok
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ($common_connstr, $connstr, $test_name) = @_;
my $cmd = [
'psql', '-X', '-A', '-t', '-c',
"SELECT \$\$connected with $connstr\$\$",
'-d', "$common_connstr $connstr"
];
command_ok($cmd, $test_name);
return;
}
sub test_connect_fails
{
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ($common_connstr, $connstr, $expected_stderr, $test_name) = @_;
my $cmd = [
'psql', '-X', '-A', '-t', '-c',
"SELECT \$\$connected with $connstr\$\$",
'-d', "$common_connstr $connstr"
];
command_fails_like($cmd, $expected_stderr, $test_name);
return;
}
# Copy a set of files, taking into account wildcards # Copy a set of files, taking into account wildcards
sub copy_files sub copy_files
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment