Add LDAP authentication test suite

Like the SSL test suite, this will not be run by default.

Reviewed-by: Thomas Munro <thomas.munro@enterprisedb.com>
This commit is contained in:
Peter Eisentraut 2017-09-15 11:41:15 -04:00
parent 71aa4801a8
commit f0e60ee4bc
6 changed files with 255 additions and 3 deletions

View File

@ -15,9 +15,10 @@ include $(top_builddir)/src/Makefile.global
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/,
# because the SSL test suite is not secure to run on a multi-user system.
ALWAYS_SUBDIRS = examples locale thread ssl
# but we do want "make clean" etc to recurse into them. Likewise for
# ldap/ and ssl/, because these test suites are not secure to run on a
# multi-user system.
ALWAYS_SUBDIRS = examples ldap locale thread ssl
# We want to recurse to all subdirs for all standard targets, except that
# installcheck and install should not recurse into the subdirectory "modules".

2
src/test/ldap/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Generated by test suite
/tmp_check/

20
src/test/ldap/Makefile Normal file
View File

@ -0,0 +1,20 @@
#-------------------------------------------------------------------------
#
# Makefile for src/test/ldap
#
# Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# src/test/ldap/Makefile
#
#-------------------------------------------------------------------------
subdir = src/test/ldap
top_builddir = ../../..
include $(top_builddir)/src/Makefile.global
check:
$(prove_check)
clean distclean maintainer-clean:
rm -rf tmp_check

20
src/test/ldap/README Normal file
View File

@ -0,0 +1,20 @@
src/test/ldap/README
Tests for LDAP functionality
============================
This directory contains a test suite for LDAP functionality. This
requires a full OpenLDAP installation, including server and client
tools, and is therefore kept separate and not run by default. You
might need to adjust some paths in the test file to have it find
OpenLDAP in a place that hadn't been thought of yet.
Also, this test suite creates an LDAP server that listens for TCP/IP
connections on localhost without any real access control, so it is not
safe to run this on a system where there might be untrusted local
users.
Running the tests
=================
make check

View File

@ -0,0 +1,32 @@
dn: dc=example,dc=net
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example
o: ExampleCo
dn: uid=test1,dc=example,dc=net
objectClass: inetOrgPerson
objectClass: posixAccount
uid: test1
sn: Lastname
givenName: Firstname
cn: First Test User
displayName: First Test User
uidNumber: 101
gidNumber: 100
homeDirectory: /home/test1
mail: test1@example.net
dn: uid=test2,dc=example,dc=net
objectClass: inetOrgPerson
objectClass: posixAccount
uid: test2
sn: Lastname
givenName: Firstname
cn: Second Test User
displayName: Second Test User
uidNumber: 102
gidNumber: 100
homeDirectory: /home/test2
mail: test2@example.net

177
src/test/ldap/t/001_auth.pl Normal file
View File

@ -0,0 +1,177 @@
use strict;
use warnings;
use TestLib;
use PostgresNode;
use Test::More tests => 14;
my ($slapd, $ldap_bin_dir, $ldap_schema_dir);
$ldap_bin_dir = undef; # usually in PATH
if ($^O eq 'darwin')
{
$slapd = '/usr/local/opt/openldap/libexec/slapd';
$ldap_schema_dir = '/usr/local/etc/openldap/schema';
}
elsif ($^O eq 'linux')
{
$slapd = '/usr/sbin/slapd';
$ldap_schema_dir = '/etc/ldap/schema' if -f '/etc/ldap/schema';
$ldap_schema_dir = '/etc/openldap/schema' if -f '/etc/openldap/schema';
}
elsif ($^O eq 'freebsd')
{
$slapd = '/usr/local/libexec/slapd';
$ldap_schema_dir = '/usr/local/etc/openldap/schema';
}
# 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 = "${TestLib::tmp_check}/openldap-data";
my $slapd_conf = "${TestLib::tmp_check}/slapd.conf";
my $slapd_pidfile = "${TestLib::tmp_check}/slapd.pid";
my $slapd_logfile = "${TestLib::tmp_check}/slapd.log";
my $ldap_conf = "${TestLib::tmp_check}/ldap.conf";
my $ldap_server = 'localhost';
my $ldap_port = int(rand() * 16384) + 49152;
my $ldap_url = "ldap://$ldap_server:$ldap_port";
my $ldap_basedn = 'dc=example,dc=net';
my $ldap_rootdn = 'cn=Manager,dc=example,dc=net';
my $ldap_rootpw = 'secret';
my $ldap_pwfile = "${TestLib::tmp_check}/ldappassword";
note "setting up slapd";
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 anonymous auth
database ldif
directory $ldap_datadir
suffix "dc=example,dc=net"
rootdn "$ldap_rootdn"
rootpw $ldap_rootpw});
mkdir $ldap_datadir or die;
system_or_bail $slapd, '-f', $slapd_conf, '-h', $ldap_url;
END
{
kill 'INT', `cat $slapd_pidfile` if -f $slapd_pidfile;
}
append_to_file($ldap_pwfile, $ldap_rootpw);
chmod 0600, $ldap_pwfile or die;
$ENV{'LDAPURI'} = $ldap_url;
$ENV{'LDAPBINDDN'} = $ldap_rootdn;
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 = get_new_node('node');
$node->init;
$node->start;
$node->safe_psql('postgres', 'CREATE USER test0;');
$node->safe_psql('postgres', 'CREATE USER test1;');
$node->safe_psql('postgres', 'CREATE USER "test2@example.net";');
note "running tests";
sub test_access
{
my ($node, $role, $expected_res, $test_name) = @_;
my $res = $node->psql('postgres', 'SELECT 1', extra_params => [ '-U', $role ]);
is($res, $expected_res, $test_name);
}
note "simple bind";
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf', qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="uid=" ldapsuffix=",dc=example,dc=net"});
$node->reload;
$ENV{"PGPASSWORD"} = 'wrong';
test_access($node, 'test0', 2, 'simple bind authentication fails if user not found in LDAP');
test_access($node, 'test1', 2, 'simple bind authentication fails with wrong password');
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'simple bind authentication succeeds');
note "search+bind";
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"});
$node->reload;
$ENV{"PGPASSWORD"} = 'wrong';
test_access($node, 'test0', 2, 'search+bind authentication fails if user not found in LDAP');
test_access($node, 'test1', 2, 'search+bind authentication fails with wrong password');
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'search+bind authentication succeeds');
note "LDAP URLs";
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf', qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn?uid?sub"});
$node->reload;
$ENV{"PGPASSWORD"} = 'wrong';
test_access($node, 'test0', 2, 'search+bind with LDAP URL authentication fails if user not found in LDAP');
test_access($node, 'test1', 2, 'search+bind with LDAP URL authentication fails with wrong password');
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'search+bind with LDAP URL authentication succeeds');
note "search filters";
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" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"});
$node->reload;
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'search filter finds by uid');
$ENV{"PGPASSWORD"} = 'secret2';
test_access($node, 'test2@example.net', 0, 'search filter finds by mail');
note "search filters in LDAP URLs";
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf', qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn??sub?(|(uid=\$username)(mail=\$username))"});
$node->reload;
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'search filter finds by uid');
$ENV{"PGPASSWORD"} = 'secret2';
test_access($node, 'test2@example.net', 0, 'search filter finds by mail');
# This is not documented: You can combine ldapurl and other ldap*
# settings. ldapurl is always parsed first, then the other settings
# override. It might be useful in a case like this.
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf('pg_hba.conf', qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn??sub" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"});
$node->reload;
$ENV{"PGPASSWORD"} = 'secret1';
test_access($node, 'test1', 0, 'combined LDAP URL and search filter');