aboutsummaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/authentication/t/001_password.pl59
-rw-r--r--src/test/kerberos/t/001_auth.pl79
-rw-r--r--src/test/ldap/t/001_auth.pl52
-rw-r--r--src/test/perl/PostgresNode.pm77
-rw-r--r--src/test/ssl/t/001_ssltests.pl36
-rw-r--r--src/test/ssl/t/002_scram.pl10
6 files changed, 247 insertions, 66 deletions
diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl
index 65303ca3f5c..150b226c0e8 100644
--- a/src/test/authentication/t/001_password.pl
+++ b/src/test/authentication/t/001_password.pl
@@ -17,7 +17,7 @@ if (!$use_unix_sockets)
}
else
{
- plan tests => 13;
+ plan tests => 23;
}
@@ -35,15 +35,12 @@ sub reset_pg_hba
return;
}
-# Test access for a single role, useful to wrap all tests into one.
+# Test access for a single role, useful to wrap all tests into one. Extra
+# named parameters are passed to connect_ok/fails as-is.
sub test_role
{
- my $node = shift;
- my $role = shift;
- my $method = shift;
- my $expected_res = shift;
+ my ($node, $role, $method, $expected_res, %params) = @_;
my $status_string = 'failed';
-
$status_string = 'success' if ($expected_res eq 0);
my $connstr = "user=$role";
@@ -52,18 +49,19 @@ sub test_role
if ($expected_res eq 0)
{
- $node->connect_ok($connstr, $testname);
+ $node->connect_ok($connstr, $testname, %params);
}
else
{
# No checks of the error message, only the status code.
- $node->connect_fails($connstr, $testname);
+ $node->connect_fails($connstr, $testname, %params);
}
}
# Initialize primary node
my $node = get_new_node('primary');
$node->init;
+$node->append_conf('postgresql.conf', "log_connections = on\n");
$node->start;
# Create 3 roles with different password methods for each one. The same
@@ -76,26 +74,51 @@ $node->safe_psql('postgres',
);
$ENV{"PGPASSWORD"} = 'pass';
-# For "trust" method, all users should be able to connect.
+# For "trust" method, all users should be able to connect. These users are not
+# considered to be authenticated.
reset_pg_hba($node, 'trust');
-test_role($node, 'scram_role', 'trust', 0);
-test_role($node, 'md5_role', 'trust', 0);
+test_role($node, 'scram_role', 'trust', 0,
+ log_unlike => [qr/connection authenticated:/]);
+test_role($node, 'md5_role', 'trust', 0,
+ log_unlike => [qr/connection authenticated:/]);
# For plain "password" method, all users should also be able to connect.
reset_pg_hba($node, 'password');
-test_role($node, 'scram_role', 'password', 0);
-test_role($node, 'md5_role', 'password', 0);
+test_role($node, 'scram_role', 'password', 0,
+ log_like =>
+ [qr/connection authenticated: identity="scram_role" method=password/]);
+test_role($node, 'md5_role', 'password', 0,
+ log_like =>
+ [qr/connection authenticated: identity="md5_role" method=password/]);
# For "scram-sha-256" method, user "scram_role" should be able to connect.
reset_pg_hba($node, 'scram-sha-256');
-test_role($node, 'scram_role', 'scram-sha-256', 0);
-test_role($node, 'md5_role', 'scram-sha-256', 2);
+test_role(
+ $node,
+ 'scram_role',
+ 'scram-sha-256',
+ 0,
+ log_like => [
+ qr/connection authenticated: identity="scram_role" method=scram-sha-256/
+ ]);
+test_role($node, 'md5_role', 'scram-sha-256', 2,
+ log_unlike => [qr/connection authenticated:/]);
+
+# Test that bad passwords are rejected.
+$ENV{"PGPASSWORD"} = 'badpass';
+test_role($node, 'scram_role', 'scram-sha-256', 2,
+ log_unlike => [qr/connection authenticated:/]);
+$ENV{"PGPASSWORD"} = 'pass';
# For "md5" method, all users should be able to connect (SCRAM
# authentication will be performed for the user with a SCRAM secret.)
reset_pg_hba($node, 'md5');
-test_role($node, 'scram_role', 'md5', 0);
-test_role($node, 'md5_role', 'md5', 0);
+test_role($node, 'scram_role', 'md5', 0,
+ log_like =>
+ [qr/connection authenticated: identity="scram_role" method=md5/]);
+test_role($node, 'md5_role', 'md5', 0,
+ log_like =>
+ [qr/connection authenticated: identity="md5_role" method=md5/]);
# Tests for channel binding without SSL.
# Using the password authentication method; channel binding can't work
diff --git a/src/test/kerberos/t/001_auth.pl b/src/test/kerberos/t/001_auth.pl
index 8db18294608..26c2c7077b3 100644
--- a/src/test/kerberos/t/001_auth.pl
+++ b/src/test/kerberos/t/001_auth.pl
@@ -20,7 +20,7 @@ use Time::HiRes qw(usleep);
if ($ENV{with_gssapi} eq 'yes')
{
- plan tests => 32;
+ plan tests => 44;
}
else
{
@@ -183,39 +183,36 @@ note "running tests";
sub test_access
{
my ($node, $role, $query, $expected_res, $gssencmode, $test_name,
- $expect_log_msg)
+ @expect_log_msgs)
= @_;
# need to connect over TCP/IP for Kerberos
my $connstr = $node->connstr('postgres')
. " user=$role host=$host hostaddr=$hostaddr $gssencmode";
+ my %params = (
+ sql => $query,
+ );
+
+ if (@expect_log_msgs)
+ {
+ # Match every message literally.
+ my @regexes = map { qr/\Q$_\E/ } @expect_log_msgs;
+
+ $params{log_like} = \@regexes;
+ }
+
if ($expected_res eq 0)
{
# The result is assumed to match "true", or "t", here.
- $node->connect_ok(
- $connstr, $test_name,
- sql => $query,
- expected_stdout => qr/^t$/);
+ $params{expected_stdout} = qr/^t$/;
+
+ $node->connect_ok($connstr, $test_name, %params);
}
else
{
- $node->connect_fails($connstr, $test_name);
+ $node->connect_fails($connstr, $test_name, %params);
}
-
- # Verify specified log message is logged in the log file.
- if ($expect_log_msg ne '')
- {
- my $first_logfile = slurp_file($node->logfile);
-
- like($first_logfile, qr/\Q$expect_log_msg\E/,
- 'found expected log file content');
- }
-
- # Clean up any existing contents in the node's log file so as
- # future tests don't step on each other's generated contents.
- truncate $node->logfile, 0;
- return;
}
# As above, but test for an arbitrary query result.
@@ -239,11 +236,19 @@ $node->append_conf('pg_hba.conf',
qq{host all all $hostaddr/32 gss map=mymap});
$node->restart;
-test_access($node, 'test1', 'SELECT true', 2, '', 'fails without ticket', '');
+test_access($node, 'test1', 'SELECT true', 2, '', 'fails without ticket');
run_log [ $kinit, 'test1' ], \$test1_password or BAIL_OUT($?);
-test_access($node, 'test1', 'SELECT true', 2, '', 'fails without mapping', '');
+test_access(
+ $node,
+ 'test1',
+ 'SELECT true',
+ 2,
+ '',
+ 'fails without mapping',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
+ "no match in usermap \"mymap\" for user \"test1\"");
$node->append_conf('pg_ident.conf', qq{mymap /^(.*)\@$realm\$ \\1});
$node->restart;
@@ -255,6 +260,7 @@ test_access(
0,
'',
'succeeds with mapping with default gssencmode and host hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
@@ -265,6 +271,7 @@ test_access(
0,
'gssencmode=prefer',
'succeeds with GSS-encrypted access preferred with host hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
test_access(
@@ -274,6 +281,7 @@ test_access(
0,
'gssencmode=require',
'succeeds with GSS-encrypted access required with host hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
@@ -310,6 +318,7 @@ test_access(
0,
'gssencmode=prefer',
'succeeds with GSS-encrypted access preferred and hostgssenc hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
test_access(
@@ -319,10 +328,11 @@ test_access(
0,
'gssencmode=require',
'succeeds with GSS-encrypted access required and hostgssenc hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
test_access($node, 'test1', 'SELECT true', 2, 'gssencmode=disable',
- 'fails with GSS encryption disabled and hostgssenc hba', '');
+ 'fails with GSS encryption disabled and hostgssenc hba');
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf',
@@ -336,10 +346,11 @@ test_access(
0,
'gssencmode=prefer',
'succeeds with GSS-encrypted access preferred and hostnogssenc hba, but no encryption',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=no, principal=test1\@$realm)"
);
test_access($node, 'test1', 'SELECT true', 2, 'gssencmode=require',
- 'fails with GSS-encrypted access required and hostnogssenc hba', '');
+ 'fails with GSS-encrypted access required and hostnogssenc hba');
test_access(
$node,
'test1',
@@ -347,6 +358,7 @@ test_access(
0,
'gssencmode=disable',
'succeeds with GSS encryption disabled and hostnogssenc hba',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=no, principal=test1\@$realm)"
);
@@ -363,5 +375,22 @@ test_access(
0,
'',
'succeeds with include_realm=0 and defaults',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss",
"connection authorized: user=$username database=$dbname application_name=$application GSS (authenticated=yes, encrypted=yes, principal=test1\@$realm)"
);
+
+# Reset pg_hba.conf, and cause a usermap failure with an authentication
+# that has passed.
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf',
+ qq{host all all $hostaddr/32 gss include_realm=0 krb_realm=EXAMPLE.ORG});
+$node->restart;
+
+test_access(
+ $node,
+ 'test1',
+ 'SELECT true',
+ 2,
+ '',
+ 'fails with wrong krb_realm, but still authenticates',
+ "connection authenticated: identity=\"test1\@$realm\" method=gss");
diff --git a/src/test/ldap/t/001_auth.pl b/src/test/ldap/t/001_auth.pl
index ad54854a422..ec4721234bc 100644
--- a/src/test/ldap/t/001_auth.pl
+++ b/src/test/ldap/t/001_auth.pl
@@ -6,7 +6,7 @@ use Test::More;
if ($ENV{with_ldap} eq 'yes')
{
- plan tests => 22;
+ plan tests => 28;
}
else
{
@@ -152,6 +152,7 @@ note "setting up PostgreSQL instance";
my $node = get_new_node('node');
$node->init;
+$node->append_conf('postgresql.conf', "log_connections = on\n");
$node->start;
$node->safe_psql('postgres', 'CREATE USER test0;');
@@ -162,17 +163,17 @@ note "running tests";
sub test_access
{
- my ($node, $role, $expected_res, $test_name) = @_;
+ my ($node, $role, $expected_res, $test_name, %params) = @_;
my $connstr = "user=$role";
if ($expected_res eq 0)
{
- $node->connect_ok($connstr, $test_name);
+ $node->connect_ok($connstr, $test_name, %params);
}
else
{
# No checks of the error message, only the status code.
- $node->connect_fails($connstr, $test_name);
+ $node->connect_fails($connstr, $test_name, %params);
}
}
@@ -185,12 +186,22 @@ $node->append_conf('pg_hba.conf',
$node->restart;
$ENV{"PGPASSWORD"} = 'wrong';
-test_access($node, 'test0', 2,
- 'simple bind authentication fails if user not found in LDAP');
-test_access($node, 'test1', 2,
- 'simple bind authentication fails with wrong password');
+test_access(
+ $node, 'test0', 2,
+ 'simple bind authentication fails if user not found in LDAP',
+ log_unlike => [qr/connection authenticated:/]);
+test_access(
+ $node, 'test1', 2,
+ 'simple bind authentication fails with wrong password',
+ log_unlike => [qr/connection authenticated:/]);
+
$ENV{"PGPASSWORD"} = 'secret1';
-test_access($node, 'test1', 0, 'simple bind authentication succeeds');
+test_access(
+ $node, 'test1', 0,
+ 'simple bind authentication succeeds',
+ log_like => [
+ qr/connection authenticated: identity="uid=test1,dc=example,dc=net" method=ldap/
+ ],);
note "search+bind";
@@ -206,7 +217,12 @@ test_access($node, 'test0', 2,
test_access($node, 'test1', 2,
'search+bind authentication fails with wrong password');
$ENV{"PGPASSWORD"} = 'secret1';
-test_access($node, 'test1', 0, 'search+bind authentication succeeds');
+test_access(
+ $node, 'test1', 0,
+ 'search+bind authentication succeeds',
+ log_like => [
+ qr/connection authenticated: identity="uid=test1,dc=example,dc=net" method=ldap/
+ ],);
note "multiple servers";
@@ -250,9 +266,21 @@ $node->append_conf('pg_hba.conf',
$node->restart;
$ENV{"PGPASSWORD"} = 'secret1';
-test_access($node, 'test1', 0, 'search filter finds by uid');
+test_access(
+ $node, 'test1', 0,
+ 'search filter finds by uid',
+ log_like => [
+ qr/connection authenticated: identity="uid=test1,dc=example,dc=net" method=ldap/
+ ],);
$ENV{"PGPASSWORD"} = 'secret2';
-test_access($node, 'test2@example.net', 0, 'search filter finds by mail');
+test_access(
+ $node,
+ 'test2@example.net',
+ 0,
+ 'search filter finds by mail',
+ log_like => [
+ qr/connection authenticated: identity="uid=test2,dc=example,dc=net" method=ldap/
+ ],);
note "search filters in LDAP URLs";
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index ec202f1b6e5..598906ad649 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -1876,6 +1876,18 @@ instead of the default.
If this regular expression is set, matches it with the output generated.
+=item log_like => [ qr/required message/ ]
+
+If given, it must be an array reference containing a list of regular
+expressions that must match against the server log, using
+C<Test::More::like()>.
+
+=item log_unlike => [ qr/prohibited message/ ]
+
+If given, it must be an array reference containing a list of regular
+expressions that must NOT match against the server log. They will be
+passed to C<Test::More::unlike()>.
+
=back
=cut
@@ -1895,6 +1907,22 @@ sub connect_ok
$sql = "SELECT \$\$connected with $connstr\$\$";
}
+ my (@log_like, @log_unlike);
+ if (defined($params{log_like}))
+ {
+ @log_like = @{ $params{log_like} };
+ }
+ if (defined($params{log_unlike}))
+ {
+ @log_unlike = @{ $params{log_unlike} };
+ }
+
+ if (@log_like or @log_unlike)
+ {
+ # Don't let previous log entries match for this connection.
+ truncate $self->logfile, 0;
+ }
+
# Never prompt for a password, any callers of this routine should
# have set up things properly, and this should not block.
my ($ret, $stdout, $stderr) = $self->psql(
@@ -1910,6 +1938,19 @@ sub connect_ok
{
like($stdout, $params{expected_stdout}, "$test_name: matches");
}
+ if (@log_like or @log_unlike)
+ {
+ my $log_contents = TestLib::slurp_file($self->logfile);
+
+ while (my $regex = shift @log_like)
+ {
+ like($log_contents, $regex, "$test_name: log matches");
+ }
+ while (my $regex = shift @log_unlike)
+ {
+ unlike($log_contents, $regex, "$test_name: log does not match");
+ }
+ }
}
=pod
@@ -1925,6 +1966,12 @@ to fail.
If this regular expression is set, matches it with the output generated.
+=item log_like => [ qr/required message/ ]
+
+=item log_unlike => [ qr/prohibited message/ ]
+
+See C<connect_ok(...)>, above.
+
=back
=cut
@@ -1934,6 +1981,22 @@ sub connect_fails
local $Test::Builder::Level = $Test::Builder::Level + 1;
my ($self, $connstr, $test_name, %params) = @_;
+ my (@log_like, @log_unlike);
+ if (defined($params{log_like}))
+ {
+ @log_like = @{ $params{log_like} };
+ }
+ if (defined($params{log_unlike}))
+ {
+ @log_unlike = @{ $params{log_unlike} };
+ }
+
+ if (@log_like or @log_unlike)
+ {
+ # Don't let previous log entries match for this connection.
+ truncate $self->logfile, 0;
+ }
+
# Never prompt for a password, any callers of this routine should
# have set up things properly, and this should not block.
my ($ret, $stdout, $stderr) = $self->psql(
@@ -1948,6 +2011,20 @@ sub connect_fails
{
like($stderr, $params{expected_stderr}, "$test_name: matches");
}
+
+ if (@log_like or @log_unlike)
+ {
+ my $log_contents = TestLib::slurp_file($self->logfile);
+
+ while (my $regex = shift @log_like)
+ {
+ like($log_contents, $regex, "$test_name: log matches");
+ }
+ while (my $regex = shift @log_unlike)
+ {
+ unlike($log_contents, $regex, "$test_name: log does not match");
+ }
+ }
}
=pod
diff --git a/src/test/ssl/t/001_ssltests.pl b/src/test/ssl/t/001_ssltests.pl
index 0decbe71774..cc797a5c98f 100644
--- a/src/test/ssl/t/001_ssltests.pl
+++ b/src/test/ssl/t/001_ssltests.pl
@@ -17,7 +17,7 @@ if ($ENV{with_ssl} ne 'openssl')
}
else
{
- plan tests => 103;
+ plan tests => 110;
}
#### Some configuration
@@ -431,7 +431,10 @@ my $dn_connstr = "$common_connstr dbname=certdb_dn";
$node->connect_ok(
"$dn_connstr 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",
+ log_like => [
+ qr/connection authenticated: identity="CN=ssltestuser-dn,OU=Testing,OU=Engineering,O=PGDG" method=cert/
+ ],);
# same thing but with a regex
$dn_connstr = "$common_connstr dbname=certdb_dn_re";
@@ -445,7 +448,11 @@ $dn_connstr = "$common_connstr dbname=certdb_cn";
$node->connect_ok(
"$dn_connstr 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",
+ # the full DN should still be used as the authenticated identity
+ log_like => [
+ qr/connection authenticated: identity="CN=ssltestuser-dn,OU=Testing,OU=Engineering,O=PGDG" method=cert/
+ ],);
@@ -511,13 +518,18 @@ $node->connect_fails(
"$common_connstr user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"certificate authorization fails with client cert belonging to another user",
expected_stderr =>
- qr/certificate authentication failed for user "anotheruser"/);
+ qr/certificate authentication failed for user "anotheruser"/,
+ # certificate authentication should be logged even on failure
+ log_like =>
+ [qr/connection authenticated: identity="CN=ssltestuser" method=cert/],);
# revoked client cert
$node->connect_fails(
"$common_connstr user=ssltestuser sslcert=ssl/client-revoked.crt sslkey=ssl/client-revoked_tmp.key",
"certificate authorization fails with revoked client cert",
- expected_stderr => qr/SSL error: sslv3 alert certificate revoked/);
+ expected_stderr => qr/SSL error: sslv3 alert certificate revoked/,
+ # revoked certificates should not authenticate the user
+ log_unlike => [qr/connection authenticated:/],);
# Check that connecting with auth-option verify-full in pg_hba:
# works, iff username matches Common Name
@@ -527,21 +539,25 @@ $common_connstr =
$node->connect_ok(
"$common_connstr 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",
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
$node->connect_fails(
"$common_connstr user=anotheruser sslcert=ssl/client.crt sslkey=ssl/client_tmp.key",
"auth_option clientcert=verify-full fails with mismatching username and Common Name",
expected_stderr =>
- qr/FATAL: .* "trust" authentication failed for user "anotheruser"/,);
+ qr/FATAL: .* "trust" authentication failed for user "anotheruser"/,
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
# Check that connecting with auth-optionverify-ca in pg_hba :
# works, when username doesn't match Common Name
$node->connect_ok(
"$common_connstr 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",
+ # verify-full does not provide authentication
+ log_unlike => [qr/connection authenticated:/],);
# intermediate client_ca.crt is provided by client, and isn't in server's ssl_ca_file
switch_server_cert($node, 'server-cn-only', 'root_ca');
diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl
index 583b62b3a18..3cb22ffced1 100644
--- a/src/test/ssl/t/002_scram.pl
+++ b/src/test/ssl/t/002_scram.pl
@@ -27,7 +27,7 @@ my $SERVERHOSTCIDR = '127.0.0.1/32';
my $supports_tls_server_end_point =
check_pg_config("#define HAVE_X509_GET_SIGNATURE_NID 1");
-my $number_of_tests = $supports_tls_server_end_point ? 9 : 10;
+my $number_of_tests = $supports_tls_server_end_point ? 11 : 12;
# Allocation of base connection string shared among multiple tests.
my $common_connstr;
@@ -102,6 +102,14 @@ $node->connect_fails(
qr/channel binding required, but server authenticated client without channel binding/
);
+# Certificate verification at the connection level should still work fine.
+$node->connect_ok(
+ "sslcert=ssl/client.crt sslkey=$client_tmp_key sslrootcert=invalid hostaddr=$SERVERHOSTADDR dbname=verifydb user=ssltestuser channel_binding=require",
+ "SCRAM with clientcert=verify-full and channel_binding=require",
+ log_like => [
+ qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/
+ ]);
+
# clean up
unlink($client_tmp_key);