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.


cheers


andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com
From 78ca6b405601ce0d884406b94fa356e38e19d2e0 Mon Sep 17 00:00:00 2001
From: Andrew Dunstan <and...@dunslane.net>
Date: Mon, 19 Dec 2022 06:38:11 -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.

Author: John Naylor
---
 src/test/ldap/meson.build         |   1 +
 src/test/ldap/t/002_bindpasswd.pl | 198 ++++++++++++++++++++++++++++++
 2 files changed, 199 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 8577385ee5..4c8df92a26 100644
--- a/src/test/ldap/meson.build
+++ b/src/test/ldap/meson.build
@@ -5,6 +5,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..0ed3a630af
--- /dev/null
+++ b/src/test/ldap/t/002_bindpasswd.pl
@@ -0,0 +1,198 @@
+
+# Copyright (c) 2022, PostgreSQL Global Development Group
+
+use strict;
+use warnings;
+use File::Copy;
+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 '/usr/local/opt/openldap')
+{
+	# typical paths for Homebrew
+	$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 $ldap_datadir  = "${PostgreSQL::Test::Utils::tmp_check}/openldap-data";
+my $slapd_certs   = "${PostgreSQL::Test::Utils::tmp_check}/slapd-certs";
+my $slapd_conf    = "${PostgreSQL::Test::Utils::tmp_check}/slapd.conf";
+my $slapd_pidfile = "${PostgreSQL::Test::Utils::tmp_check}/slapd.pid";
+my $slapd_logfile = "${PostgreSQL::Test::Utils::log_path}/slapd.log";
+my $ldap_conf     = "${PostgreSQL::Test::Utils::tmp_check}/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   = "${PostgreSQL::Test::Utils::tmp_check}/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});
+
+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;
+}
+
+# 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 "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

Reply via email to