|
| 1 | + |
| 2 | +# Copyright (c) 2021-2022, PostgreSQL Global Development Group |
| 3 | + |
| 4 | +# Tests for peer authentication and user name map. |
| 5 | +# The test is skipped if the platform does not support peer authentication. |
| 6 | + |
| 7 | +use strict; |
| 8 | +use warnings; |
| 9 | +use PostgreSQL::Test::Cluster; |
| 10 | +use PostgreSQL::Test::Utils; |
| 11 | +use Test::More; |
| 12 | + |
| 13 | +# Delete pg_hba.conf from the given node, add a new entry to it |
| 14 | +# and then execute a reload to refresh it. |
| 15 | +sub reset_pg_hba |
| 16 | +{ |
| 17 | + my $node = shift; |
| 18 | + my $hba_method = shift; |
| 19 | + |
| 20 | + unlink($node->data_dir . '/pg_hba.conf'); |
| 21 | + $node->append_conf('pg_hba.conf', "local all all $hba_method"); |
| 22 | + $node->reload; |
| 23 | + return; |
| 24 | +} |
| 25 | + |
| 26 | +# Test access for a single role, useful to wrap all tests into one. |
| 27 | +sub test_role |
| 28 | +{ |
| 29 | + local $Test::Builder::Level = $Test::Builder::Level + 1; |
| 30 | + |
| 31 | + my ($node, $role, $method, $expected_res, %params) = @_; |
| 32 | + my $status_string = 'failed'; |
| 33 | + $status_string = 'success' if ($expected_res eq 0); |
| 34 | + |
| 35 | + my $connstr = "user=$role"; |
| 36 | + my $testname = |
| 37 | + "authentication $status_string for method $method, role $role"; |
| 38 | + |
| 39 | + if ($expected_res eq 0) |
| 40 | + { |
| 41 | + $node->connect_ok($connstr, $testname, %params); |
| 42 | + } |
| 43 | + else |
| 44 | + { |
| 45 | + # No checks of the error message, only the status code. |
| 46 | + $node->connect_fails($connstr, $testname, %params); |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +# Find $pattern in log file of $node. |
| 51 | +sub find_in_log |
| 52 | +{ |
| 53 | + my ($node, $offset, $pattern) = @_; |
| 54 | + |
| 55 | + my $log = PostgreSQL::Test::Utils::slurp_file($node->logfile, $offset); |
| 56 | + return 0 if (length($log) <= 0); |
| 57 | + |
| 58 | + return $log =~ m/$pattern/; |
| 59 | +} |
| 60 | + |
| 61 | +my $node = PostgreSQL::Test::Cluster->new('node'); |
| 62 | +$node->init; |
| 63 | +$node->append_conf('postgresql.conf', "log_connections = on\n"); |
| 64 | +$node->start; |
| 65 | + |
| 66 | +# Set pg_hba.conf with the peer authentication. |
| 67 | +reset_pg_hba($node, 'peer'); |
| 68 | + |
| 69 | +# Check if peer authentication is supported on this platform. |
| 70 | +my $log_offset = -s $node->logfile; |
| 71 | +$node->psql('postgres'); |
| 72 | +if (find_in_log( |
| 73 | + $node, $log_offset, |
| 74 | + qr/peer authentication is not supported on this platform/)) |
| 75 | +{ |
| 76 | + plan skip_all => 'peer authentication is not supported on this platform'; |
| 77 | +} |
| 78 | + |
| 79 | +# Add a database role, to use for the user name map. |
| 80 | +$node->safe_psql('postgres', qq{CREATE ROLE testmapuser LOGIN}); |
| 81 | + |
| 82 | +# Extract as well the system user for the user name map. |
| 83 | +my $system_user = |
| 84 | + $node->safe_psql('postgres', |
| 85 | + q(select (string_to_array(SYSTEM_USER, ':'))[2])); |
| 86 | + |
| 87 | +# Tests without the user name map. |
| 88 | +# Failure as connection is attempted with a database role not mapping |
| 89 | +# to an authorized system user. |
| 90 | +test_role($node, qq{testmapuser}, 'peer', 2, |
| 91 | + log_like => [qr/Peer authentication failed for user "testmapuser"/]); |
| 92 | + |
| 93 | +# Tests with a user name map. |
| 94 | +$node->append_conf('pg_ident.conf', qq{mypeermap $system_user testmapuser}); |
| 95 | +reset_pg_hba($node, 'peer map=mypeermap'); |
| 96 | + |
| 97 | +# Success as the database role matches with the system user in the map. |
| 98 | +test_role($node, qq{testmapuser}, 'peer', 0, |
| 99 | + log_like => |
| 100 | + [qr/connection authenticated: identity="$system_user" method=peer/]); |
| 101 | + |
| 102 | +done_testing(); |
0 commit comments