From 284cbaea7c4b89ce8685a148baeaf1d7896a900e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 17 Nov 2023 14:40:13 +0100 Subject: [PATCH] Allow tests to pass in OpenSSL FIPS mode (TAP tests) Some tests using md5 authentication have to be skipped. In other cases, we can rewrite the tests to use a different authentication method. Reviewed-by: Tom Lane Reviewed-by: Daniel Gustafsson Discussion: https://www.postgresql.org/message-id/flat/dbbd927f-ef1f-c9a1-4ec6-c759778ac852%40enterprisedb.com --- src/test/authentication/t/001_password.pl | 146 +++++++++++++--------- src/test/ssl/t/002_scram.pl | 35 ++++-- 2 files changed, 112 insertions(+), 69 deletions(-) diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl index 891860886a..320e45ef84 100644 --- a/src/test/authentication/t/001_password.pl +++ b/src/test/authentication/t/001_password.pl @@ -66,24 +66,33 @@ $node->init; $node->append_conf('postgresql.conf', "log_connections = on\n"); $node->start; +# could fail in FIPS mode +my $md5_works = ($node->psql('postgres', "select md5('')") == 0); + # Create 3 roles with different password methods for each one. The same # password is used for all of them. -$node->safe_psql('postgres', - "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';" -); -$node->safe_psql('postgres', - "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';" -); +is( $node->psql( + 'postgres', + "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';" + ), + 0, + 'created user with SCRAM password'); +is( $node->psql( + 'postgres', + "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';" + ), + $md5_works ? 0 : 3, + 'created user with md5 password'); # Set up a table for tests of SYSTEM_USER. $node->safe_psql( 'postgres', "CREATE TABLE sysuser_data (n) AS SELECT NULL FROM generate_series(1, 10); - GRANT ALL ON sysuser_data TO md5_role;"); + GRANT ALL ON sysuser_data TO scram_role;"); $ENV{"PGPASSWORD"} = 'pass'; # Create a role that contains a comma to stress the parsing. $node->safe_psql('postgres', - q{SET password_encryption='md5'; CREATE ROLE "md5,role" LOGIN PASSWORD 'pass';} + q{SET password_encryption='scram-sha-256'; CREATE ROLE "scram,role" LOGIN PASSWORD 'pass';} ); # Create a role with a non-default iteration count @@ -141,8 +150,13 @@ reset_pg_hba($node, 'all', 'all', 'trust'); test_conn($node, 'user=scram_role', 'trust', 0, log_like => [qr/connection authenticated: user="scram_role" method=trust/]); -test_conn($node, 'user=md5_role', 'trust', 0, - log_like => [qr/connection authenticated: user="md5_role" method=trust/]); +SKIP: +{ + skip "MD5 not supported" unless $md5_works; + test_conn($node, 'user=md5_role', 'trust', 0, + log_like => + [qr/connection authenticated: user="md5_role" method=trust/]); +} # SYSTEM_USER is null when not authenticated. $res = $node->safe_psql('postgres', "SELECT SYSTEM_USER IS NULL;"); @@ -157,7 +171,7 @@ $res = $node->safe_psql( SET max_parallel_workers_per_gather TO 2; SELECT bool_and(SYSTEM_USER IS NOT DISTINCT FROM n) FROM sysuser_data;), - connstr => "user=md5_role"); + connstr => "user=scram_role"); is($res, 't', "users with trust authentication use SYSTEM_USER = NULL in parallel workers" ); @@ -275,9 +289,14 @@ reset_pg_hba($node, 'all', 'all', 'password'); test_conn($node, 'user=scram_role', 'password', 0, log_like => [qr/connection authenticated: identity="scram_role" method=password/]); -test_conn($node, 'user=md5_role', 'password', 0, - log_like => - [qr/connection authenticated: identity="md5_role" method=password/]); +SKIP: +{ + skip "MD5 not supported" unless $md5_works; + test_conn($node, 'user=md5_role', 'password', 0, + log_like => + [qr/connection authenticated: identity="md5_role" method=password/] + ); +} # require_auth succeeds here with a plaintext password. $node->connect_ok("user=scram_role require_auth=password", @@ -393,59 +412,64 @@ reset_pg_hba($node, 'all', 'all', 'md5'); test_conn($node, 'user=scram_role', 'md5', 0, log_like => [qr/connection authenticated: identity="scram_role" method=md5/]); -test_conn($node, 'user=md5_role', 'md5', 0, - log_like => - [qr/connection authenticated: identity="md5_role" method=md5/]); +SKIP: +{ + skip "MD5 not supported" unless $md5_works; + test_conn($node, 'user=md5_role', 'md5', 0, + log_like => + [qr/connection authenticated: identity="md5_role" method=md5/]); +} -# require_auth succeeds with MD5 required. -$node->connect_ok("user=md5_role require_auth=md5", - "MD5 authentication required, works with MD5 auth"); -$node->connect_ok("user=md5_role require_auth=!none", - "any authentication required, works with MD5 auth"); +# require_auth succeeds with SCRAM required. $node->connect_ok( - "user=md5_role require_auth=md5,scram-sha-256,password", - "multiple authentication types required, works with MD5 auth"); + "user=scram_role require_auth=scram-sha-256", + "SCRAM authentication required, works with SCRAM auth"); +$node->connect_ok("user=scram_role require_auth=!none", + "any authentication required, works with SCRAM auth"); +$node->connect_ok( + "user=scram_role require_auth=md5,scram-sha-256,password", + "multiple authentication types required, works with SCRAM auth"); # Authentication fails if other types are required. $node->connect_fails( - "user=md5_role require_auth=password", - "password authentication required, fails with MD5 auth", + "user=scram_role require_auth=password", + "password authentication required, fails with SCRAM auth", expected_stderr => - qr/authentication method requirement "password" failed: server requested a hashed password/ + qr/authentication method requirement "password" failed: server requested SASL authentication/ ); $node->connect_fails( - "user=md5_role require_auth=scram-sha-256", - "SCRAM authentication required, fails with MD5 auth", + "user=scram_role require_auth=md5", + "MD5 authentication required, fails with SCRAM auth", expected_stderr => - qr/authentication method requirement "scram-sha-256" failed: server requested a hashed password/ + qr/authentication method requirement "md5" failed: server requested SASL authentication/ ); $node->connect_fails( - "user=md5_role require_auth=none", - "all authentication types forbidden, fails with MD5 auth", + "user=scram_role require_auth=none", + "all authentication types forbidden, fails with SCRAM auth", expected_stderr => - qr/authentication method requirement "none" failed: server requested a hashed password/ + qr/authentication method requirement "none" failed: server requested SASL authentication/ ); -# Authentication fails if MD5 is forbidden. +# Authentication fails if SCRAM is forbidden. $node->connect_fails( - "user=md5_role require_auth=!md5", - "password authentication forbidden, fails with MD5 auth", + "user=scram_role require_auth=!scram-sha-256", + "password authentication forbidden, fails with SCRAM auth", expected_stderr => - qr/authentication method requirement "!md5" failed: server requested a hashed password/ + qr/authentication method requirement "!scram-sha-256" failed: server requested SASL authentication/ ); $node->connect_fails( - "user=md5_role require_auth=!password,!md5,!scram-sha-256", - "multiple authentication types forbidden, fails with MD5 auth", + "user=scram_role require_auth=!password,!md5,!scram-sha-256", + "multiple authentication types forbidden, fails with SCRAM auth", expected_stderr => - qr/authentication method requirement "!password,!md5,!scram-sha-256" failed: server requested a hashed password/ + qr/authentication method requirement "!password,!md5,!scram-sha-256" failed: server requested SASL authentication/ ); # Test SYSTEM_USER <> NULL with parallel workers. $node->safe_psql( 'postgres', "TRUNCATE sysuser_data; -INSERT INTO sysuser_data SELECT 'md5:md5_role' FROM generate_series(1, 10);", - connstr => "user=md5_role"); +INSERT INTO sysuser_data SELECT 'md5:scram_role' FROM generate_series(1, 10);", + connstr => "user=scram_role"); $res = $node->safe_psql( 'postgres', qq( SET min_parallel_table_scan_size TO 0; @@ -454,7 +478,7 @@ $res = $node->safe_psql( SET max_parallel_workers_per_gather TO 2; SELECT bool_and(SYSTEM_USER IS NOT DISTINCT FROM n) FROM sysuser_data;), - connstr => "user=md5_role"); + connstr => "user=scram_role"); is($res, 't', "users with md5 authentication use SYSTEM_USER = md5:role in parallel workers" ); @@ -490,49 +514,57 @@ test_conn($node, 'user=md5_role', 'password from pgpass', 2); append_to_file( $pgpassfile, qq! -*:*:*:md5_role:p\\ass -*:*:*:md5,role:p\\ass +*:*:*:scram_role:p\\ass +*:*:*:scram,role:p\\ass !); -test_conn($node, 'user=md5_role', 'password from pgpass', 0); +test_conn($node, 'user=scram_role', 'password from pgpass', 0); # Testing with regular expression for username. The third regexp matches. -reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^md.*$', 'password'); -test_conn($node, 'user=md5_role', 'password, matching regexp for username', 0, +reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^scr.*$', 'password'); +test_conn( + $node, + 'user=scram_role', + 'password, matching regexp for username', + 0, log_like => - [qr/connection authenticated: identity="md5_role" method=password/]); + [qr/connection authenticated: identity="scram_role" method=password/]); # The third regex does not match anymore. -reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^m_d.*$', 'password'); -test_conn($node, 'user=md5_role', +reset_pg_hba($node, 'all', '/^.*nomatch.*$, baduser, /^sc_r.*$', 'password'); +test_conn($node, 'user=scram_role', 'password, non matching regexp for username', 2, log_unlike => [qr/connection authenticated:/]); # Test with a comma in the regular expression. In this case, the use of # double quotes is mandatory so as this is not considered as two elements # of the user name list when parsing pg_hba.conf. -reset_pg_hba($node, 'all', '"/^.*5,.*e$"', 'password'); -test_conn($node, 'user=md5,role', 'password, matching regexp for username', 0, +reset_pg_hba($node, 'all', '"/^.*m,.*e$"', 'password'); +test_conn( + $node, + 'user=scram,role', + 'password, matching regexp for username', + 0, log_like => - [qr/connection authenticated: identity="md5,role" method=password/]); + [qr/connection authenticated: identity="scram,role" method=password/]); # Testing with regular expression for dbname. The third regex matches. reset_pg_hba($node, '/^.*nomatch.*$, baddb, /^regex_t.*b$', 'all', 'password'); test_conn( $node, - 'user=md5_role dbname=regex_testdb', + 'user=scram_role dbname=regex_testdb', 'password, matching regexp for dbname', 0, log_like => - [qr/connection authenticated: identity="md5_role" method=password/]); + [qr/connection authenticated: identity="scram_role" method=password/]); # The third regexp does not match anymore. reset_pg_hba($node, '/^.*nomatch.*$, baddb, /^regex_t.*ba$', 'all', 'password'); test_conn( $node, - 'user=md5_role dbname=regex_testdb', + 'user=scram_role dbname=regex_testdb', 'password, non matching regexp for dbname', 2, log_unlike => [qr/connection authenticated:/]); diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl index 27abd02abf..91e771ec47 100644 --- a/src/test/ssl/t/002_scram.pl +++ b/src/test/ssl/t/002_scram.pl @@ -64,6 +64,9 @@ $ENV{PGHOST} = $node->host; $ENV{PGPORT} = $node->port; $node->start; +# could fail in FIPS mode +my $md5_works = ($node->psql('postgres', "select md5('')") == 0); + # Configure server for SSL connections, with password handling. $ssl_server->configure_test_server_for_ssl( $node, $SERVERHOSTADDR, $SERVERHOSTCIDR, @@ -91,12 +94,16 @@ $node->connect_ok("$common_connstr user=ssltestuser channel_binding=require", "SCRAM with SSL and channel_binding=require"); # Now test when the user has an MD5-encrypted password; should fail -$node->connect_fails( - "$common_connstr user=md5testuser channel_binding=require", - "MD5 with SSL and channel_binding=require", - expected_stderr => - qr/channel binding required but not supported by server's authentication request/ -); +SKIP: +{ + skip "MD5 not supported" unless $md5_works; + $node->connect_fails( + "$common_connstr user=md5testuser channel_binding=require", + "MD5 with SSL and channel_binding=require", + expected_stderr => + qr/channel binding required but not supported by server's authentication request/ + ); +} # Now test with auth method 'cert' by connecting to 'certdb'. Should fail, # because channel binding is not performed. Note that ssl/client.key may @@ -130,12 +137,16 @@ $node->connect_ok( "$common_connstr user=ssltestuser channel_binding=disable require_auth=scram-sha-256", "SCRAM with SSL, channel_binding=disable, and require_auth=scram-sha-256" ); -$node->connect_fails( - "$common_connstr user=md5testuser require_auth=md5 channel_binding=require", - "channel_binding can fail even when require_auth succeeds", - expected_stderr => - qr/channel binding required but not supported by server's authentication request/ -); +SKIP: +{ + skip "MD5 not supported" unless $md5_works; + $node->connect_fails( + "$common_connstr user=md5testuser require_auth=md5 channel_binding=require", + "channel_binding can fail even when require_auth succeeds", + expected_stderr => + qr/channel binding required but not supported by server's authentication request/ + ); +} $node->connect_ok( "$common_connstr user=ssltestuser channel_binding=require require_auth=scram-sha-256", "SCRAM with SSL, channel_binding=require, and require_auth=scram-sha-256"