On 2023-01-01 Su 18:31, Andrew Dunstan wrote: > On 2023-01-01 Su 14:02, Thomas Munro wrote: >> On Mon, Jan 2, 2023 at 3:04 AM Andrew Dunstan <and...@dunslane.net> wrote: >>> On 2022-12-19 Mo 11:16, Andrew Dunstan wrote: >>>> There is currently no test for the use of ldapbindpasswd in the >>>> pg_hba.conf file. This patch, mostly the work of John Naylor, remedies >>>> that. >>>> >>>> >>> This currently has failures on the cfbot for meson builds on FBSD13 and >>> Debian Bullseye, but it's not at all clear why. In both cases it fails >>> where the ldap server is started. >> I think it's failing when using meson. I guess it fails to fail on >> macOS only because you need to add a new path for Homebrew/ARM like >> commit 14d63dd2, so it's skipping (it'd be nice if we didn't need >> another copy of all that logic). Trying locally... it looks like >> slapd is failing silently, and with some tracing I can see it's >> sending an error message to my syslog daemon, which logged: >> >> 2023-01-02T07:50:20.853019+13:00 x1 slapd[153599]: main: TLS init def >> ctx failed: -1 >> >> Ah, it looks like this test is relying on "slapd-certs", which doesn't exist: >> >> tmunro@x1:~/projects/postgresql/build$ ls testrun/ldap/001_auth/data/ >> ldap.conf ldappassword openldap-data portlock slapd-certs slapd.conf >> tmunro@x1:~/projects/postgresql/build$ ls testrun/ldap/002_bindpasswd/data/ >> portlock slapd.conf >> >> I didn't look closely, but apparently there is something wrong in the >> part that copies certs from the ssl test? Not sure why it works for >> autoconf... > > > Let's see how we fare with this patch. > >
Not so well :-(. This version tries to make the tests totally independent, as they should be. That's an attempt to get the cfbot to go green, but I am intending to refactor this code substantially so the common bits are in a module each test file will load. cheers andrew -- Andrew Dunstan EDB: https://www.enterprisedb.com
From c2bedfd8a5b326ffb563da49b7b4b4006ddac361 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan <and...@dunslane.net> Date: Mon, 2 Jan 2023 09:41:06 -0500 Subject: [PATCH] Add a test for ldapbindpasswd The existing LDAP tests don't cover the use of ldapbindpasswd in pg_hba.conf, so remedy that. Authors: John Naylor and Andrew Dunstan --- src/test/ldap/meson.build | 1 + src/test/ldap/t/002_bindpasswd.pl | 223 ++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 src/test/ldap/t/002_bindpasswd.pl diff --git a/src/test/ldap/meson.build b/src/test/ldap/meson.build index 90d88138e7..7628a9c7c6 100644 --- a/src/test/ldap/meson.build +++ b/src/test/ldap/meson.build @@ -7,6 +7,7 @@ tests += { 'tap': { 'tests': [ 't/001_auth.pl', + 't/002_bindpasswd.pl', ], 'env': { 'with_ldap': ldap.found() ? 'yes' : 'no', diff --git a/src/test/ldap/t/002_bindpasswd.pl b/src/test/ldap/t/002_bindpasswd.pl new file mode 100644 index 0000000000..330a2b7dad --- /dev/null +++ b/src/test/ldap/t/002_bindpasswd.pl @@ -0,0 +1,223 @@ + +# Copyright (c) 2022, PostgreSQL Global Development Group + +use strict; +use warnings; +use File::Copy; +use File::Basename; +use PostgreSQL::Test::Utils; +use PostgreSQL::Test::Cluster; +use Test::More; + + +my ($slapd, $ldap_bin_dir, $ldap_schema_dir); + +$ldap_bin_dir = undef; # usually in PATH + +if ($ENV{with_ldap} ne 'yes') +{ + plan skip_all => 'LDAP not supported by this build'; +} +elsif ($ENV{PG_TEST_EXTRA} !~ /\bldap\b/) +{ + plan skip_all => 'Potentially unsafe test LDAP not enabled in PG_TEST_EXTRA'; +} +elsif ($^O eq 'darwin' && -d '/opt/homebrew/opt/openldap') +{ + # typical paths for Homebrew on ARM + $slapd = '/opt/homebrew/opt/openldap/libexec/slapd'; + $ldap_schema_dir = '/opt/homebrew/etc/openldap/schema'; +} +elsif ($^O eq 'darwin' && -d '/usr/local/opt/openldap') +{ + # typical paths for Homebrew on Intel + $slapd = '/usr/local/opt/openldap/libexec/slapd'; + $ldap_schema_dir = '/usr/local/etc/openldap/schema'; +} +elsif ($^O eq 'darwin' && -d '/opt/local/etc/openldap') +{ + # typical paths for MacPorts + $slapd = '/opt/local/libexec/slapd'; + $ldap_schema_dir = '/opt/local/etc/openldap/schema'; +} +elsif ($^O eq 'linux') +{ + $slapd = '/usr/sbin/slapd'; + $ldap_schema_dir = '/etc/ldap/schema' if -d '/etc/ldap/schema'; + $ldap_schema_dir = '/etc/openldap/schema' if -d '/etc/openldap/schema'; +} +elsif ($^O eq 'freebsd') +{ + $slapd = '/usr/local/libexec/slapd'; + $ldap_schema_dir = '/usr/local/etc/openldap/schema'; +} +elsif ($^O eq 'openbsd') +{ + $slapd = '/usr/local/libexec/slapd'; + $ldap_schema_dir = '/usr/local/share/examples/openldap/schema'; +} +else +{ + plan skip_all => + "ldap tests not supported on $^O or dependencies not installed"; +} + +# make your own edits here +#$slapd = ''; +#$ldap_bin_dir = ''; +#$ldap_schema_dir = ''; + +$ENV{PATH} = "$ldap_bin_dir:$ENV{PATH}" if $ldap_bin_dir; + +my $tst_name = basename(__FILE__,'.pl'); +my $test_temp = PostgreSQL::Test::Utils::tempdir("ldap-$tst_name"); + +my $ldap_datadir = "$test_temp/openldap-data"; +my $slapd_certs = "$test_temp/slapd-certs"; +my $slapd_conf = "$test_temp/slapd.conf"; +my $slapd_pidfile = "$test_temp/slapd.pid"; +my $slapd_logfile = "${PostgreSQL::Test::Utils::log_path}/slapd-2.log"; +my $ldap_conf = "$test_temp/ldap.conf"; +my $ldap_server = 'localhost'; +my $ldap_port = PostgreSQL::Test::Cluster::get_free_port(); +my $ldaps_port = PostgreSQL::Test::Cluster::get_free_port(); +my $ldap_url = "ldap://$ldap_server:$ldap_port"; +my $ldaps_url = "ldaps://$ldap_server:$ldaps_port"; +my $ldap_basedn = 'dc=example,dc=net'; +my $ldap_rootdn = 'cn=Manager,dc=example,dc=net'; +my $ldap_rootpw = 'secret'; +my $ldap_pwfile = "$test_temp/ldappassword"; + +note "setting up slapd"; + +# need to create new config without anonymous auth +unlink $slapd_conf; + +append_to_file( + $slapd_conf, + qq{include $ldap_schema_dir/core.schema +include $ldap_schema_dir/cosine.schema +include $ldap_schema_dir/nis.schema +include $ldap_schema_dir/inetorgperson.schema + +pidfile $slapd_pidfile +logfile $slapd_logfile + +access to * + by * read + by users auth + +database ldif +directory $ldap_datadir + +TLSCACertificateFile $slapd_certs/ca.crt +TLSCertificateFile $slapd_certs/server.crt +TLSCertificateKeyFile $slapd_certs/server.key + +suffix "dc=example,dc=net" +rootdn "$ldap_rootdn" +rootpw $ldap_rootpw}); + +mkdir $ldap_datadir or die "making $ldap_datadir: $!"; +mkdir $slapd_certs or die "making $slapd_certs: $!"; + +copy "../ssl/ssl/server_ca.crt", "$slapd_certs/ca.crt" + || die "copying ca.crt: $!"; +copy "../ssl/ssl/server-cn-only.crt", "$slapd_certs/server.crt" + || die "copying server.crt: $!";; +copy "../ssl/ssl/server-cn-only.key", "$slapd_certs/server.key" + || die "copying server.key: $!";; + +system_or_bail $slapd, '-f', $slapd_conf, '-h', "$ldap_url $ldaps_url"; + +END +{ + kill 'INT', `cat $slapd_pidfile` if -f $slapd_pidfile; +} + +append_to_file($ldap_pwfile, $ldap_rootpw); +chmod 0600, $ldap_pwfile or die; + +# wait until slapd accepts requests +my $retries = 0; +while (1) +{ + last + if ( + system_log( + "ldapsearch", "-sbase", + "-H", $ldap_url, + "-b", $ldap_basedn, + "-D", $ldap_rootdn, + "-y", $ldap_pwfile, + "-n", "'objectclass=*'") == 0); + die "cannot connect to slapd" if ++$retries >= 300; + note "waiting for slapd to accept requests..."; + Time::HiRes::usleep(1000000); +} + +$ENV{'LDAPURI'} = $ldap_url; +$ENV{'LDAPBINDDN'} = $ldap_rootdn; +$ENV{'LDAPCONF'} = $ldap_conf; + +# use same data as 001 test + +note "loading LDAP data"; + +system_or_bail 'ldapadd', '-x', '-y', $ldap_pwfile, '-f', 'authdata.ldif'; +system_or_bail 'ldappasswd', '-x', '-y', $ldap_pwfile, '-s', 'secret1', + 'uid=test1,dc=example,dc=net'; +system_or_bail 'ldappasswd', '-x', '-y', $ldap_pwfile, '-s', 'secret2', + 'uid=test2,dc=example,dc=net'; + +note "setting up PostgreSQL instance"; + +my $node = PostgreSQL::Test::Cluster->new('node'); +$node->init; +$node->append_conf('postgresql.conf', "log_connections = on\n"); +$node->start; + +$node->safe_psql('postgres', 'CREATE USER test0;'); +$node->safe_psql('postgres', 'CREATE USER test1;'); +$node->safe_psql('postgres', 'CREATE USER "te...@example.net";'); + +note "running tests"; + +sub test_access +{ + local $Test::Builder::Level = $Test::Builder::Level + 1; + + my ($node, $role, $expected_res, $test_name, %params) = @_; + my $connstr = "user=$role"; + + if ($expected_res eq 0) + { + $node->connect_ok($connstr, $test_name, %params); + } + else + { + # No checks of the error message, only the status code. + $node->connect_fails($connstr, $test_name, %params); + } +} + +note "use ldapbindpasswd"; + +unlink($node->data_dir . '/pg_hba.conf'); +$node->append_conf('pg_hba.conf', + qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapbinddn="$ldap_rootdn" ldapbindpasswd=wrong} +); +$node->restart; + +$ENV{"PGPASSWORD"} = 'secret1'; +test_access($node, 'test1', 2, 'search+bind authentication fails with wrong ldapbindpasswd'); + +unlink($node->data_dir . '/pg_hba.conf'); +$node->append_conf('pg_hba.conf', + qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapbinddn="$ldap_rootdn" ldapbindpasswd="$ldap_rootpw"} +); +$node->restart; + +test_access($node, 'test1', 0, 'search+bind authentication succeeds with ldapbindpasswd'); + +done_testing(); -- 2.34.1