From aa7464d949bf69ce1e8697f77400ff6b7ebb2d18 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 17 Mar 2017 11:34:16 +0200 Subject: [PATCH] Add TAP tests for password-based authentication methods. Tests all combinations of users with MD5, plaintext and SCRAM verifiers stored in pg_authid, with plain 'password', 'md5' and 'scram' authentication methods. Michael Paquier --- src/test/Makefile | 2 +- src/test/README | 3 + src/test/authentication/Makefile | 20 ++++++ src/test/authentication/README | 16 +++++ src/test/authentication/t/001_password.pl | 84 +++++++++++++++++++++++ 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 src/test/authentication/Makefile create mode 100644 src/test/authentication/README create mode 100644 src/test/authentication/t/001_password.pl diff --git a/src/test/Makefile b/src/test/Makefile index 3c2215849e..dbfa799a84 100644 --- a/src/test/Makefile +++ b/src/test/Makefile @@ -12,7 +12,7 @@ subdir = src/test top_builddir = ../.. include $(top_builddir)/src/Makefile.global -SUBDIRS = perl regress isolation modules recovery subscription +SUBDIRS = perl regress isolation modules authentication recovery subscription # We don't build or execute examples/, locale/, or thread/ by default, # but we do want "make clean" etc to recurse into them. Likewise for ssl/, diff --git a/src/test/README b/src/test/README index 0019782fb1..b5ccfc0cf6 100644 --- a/src/test/README +++ b/src/test/README @@ -8,6 +8,9 @@ individual contrib/ modules and in src/bin. Not all these tests get run by "make check". Check src/test/Makefile to see which tests get run automatically. +authentication/ + Tests for authentication + examples/ Demonstration programs for libpq that double as regression tests via "make check" diff --git a/src/test/authentication/Makefile b/src/test/authentication/Makefile new file mode 100644 index 0000000000..21ad15bea9 --- /dev/null +++ b/src/test/authentication/Makefile @@ -0,0 +1,20 @@ +#------------------------------------------------------------------------- +# +# Makefile for src/test/authentication +# +# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group +# Portions Copyright (c) 1994, Regents of the University of California +# +# src/test/authentication/Makefile +# +#------------------------------------------------------------------------- + +subdir = src/test/authentication +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +check: + $(prove_check) + +clean distclean maintainer-clean: + rm -rf tmp_check diff --git a/src/test/authentication/README b/src/test/authentication/README new file mode 100644 index 0000000000..5cffc7dc49 --- /dev/null +++ b/src/test/authentication/README @@ -0,0 +1,16 @@ +src/test/authentication/README + +Regression tests for authentication +=================================== + +This directory contains a test suite for authentication. SSL certificate +authentication tests are kept separate, in src/test/ssl/, because they +are more complicated, and are not safe to run in a multi-user system. + + +Running the tests +================= + + make check + +NOTE: This requires the --enable-tap-tests argument to configure. diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl new file mode 100644 index 0000000000..8726a23e0d --- /dev/null +++ b/src/test/authentication/t/001_password.pl @@ -0,0 +1,84 @@ +# Set of tests for authentication and pg_hba.conf. The following password +# methods are checked through this test: +# - Plain +# - MD5-encrypted +# - SCRAM-encrypted +# This test cannot run on Windows as Postgres cannot be set up with Unix +# sockets and needs to go through SSPI. + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 12; + +# Delete pg_hba.conf from the given node, add a new entry to it +# and then execute a reload to refresh it. +sub reset_pg_hba +{ + my $node = shift; + my $hba_method = shift; + + unlink($node->data_dir . '/pg_hba.conf'); + $node->append_conf('pg_hba.conf', "local all all $hba_method"); + $node->reload; +} + +# Test access for a single role, useful to wrap all tests into one. +sub test_role +{ + my $node = shift; + my $role = shift; + my $method = shift; + my $expected_res = shift; + my $status_string = 'failed'; + + $status_string = 'success' if ($expected_res eq 0); + + my $res = $node->psql('postgres', 'SELECT 1', extra_params => ['-U', $role]); + is($res, $expected_res, + "authentication $status_string for method $method, role $role"); +} + +SKIP: +{ + skip "authentication tests cannot run on Windows", 12 if ($windows_os); + + # Initialize master node + my $node = get_new_node('master'); + $node->init; + $node->start; + + # 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'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"); + $node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';"); + $node->safe_psql('postgres', "SET password_encryption='plain'; CREATE ROLE plain_role LOGIN PASSWORD 'pass';"); + $ENV{"PGPASSWORD"} = 'pass'; + + # For "trust" method, all users should be able to connect. + reset_pg_hba($node, 'trust'); + test_role($node, 'scram_role', 'trust', 0); + test_role($node, 'md5_role', 'trust', 0); + test_role($node, 'plain_role', 'trust', 0); + + # 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, 'plain_role', 'password', 0); + + # For "scram" method, user "plain_role" and "scram_role" should be able to + # connect. + reset_pg_hba($node, 'scram'); + test_role($node, 'scram_role', 'scram', 0); + test_role($node, 'md5_role', 'scram', 2); + test_role($node, 'plain_role', 'scram', 0); + + # For "md5" method, users "plain_role" and "md5_role" should be able to + # connect. + reset_pg_hba($node, 'md5'); + test_role($node, 'scram_role', 'md5', 2); + test_role($node, 'md5_role', 'md5', 0); + test_role($node, 'plain_role', 'md5', 0); +}