mirror of
https://github.com/postgres/postgres.git
synced 2025-05-20 05:13:53 +03:00
Restructure Ldap TAP test
The code for detecting the Ldap installation and setting up a test server is broken out into a reusable module that can be used for additional tests to be added in later patches. Discussion: https://postgr.es/m/06005bfb-0fd7-9d08-e0e5-440f277b73b4@dunslane.net
This commit is contained in:
parent
b90f0b5747
commit
ee4613d2b7
320
src/test/ldap/LdapServer.pm
Normal file
320
src/test/ldap/LdapServer.pm
Normal file
@ -0,0 +1,320 @@
|
||||
|
||||
############################################################################
|
||||
#
|
||||
# LdapServer.pm
|
||||
#
|
||||
# Module to set up an LDAP server for testing pg_hba.conf ldap authentication
|
||||
#
|
||||
# Copyright (c) 2023, PostgreSQL Global Development Group
|
||||
#
|
||||
############################################################################
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
LdapServer - class for an LDAP server for testing pg_hba.conf authentication
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use LdapServer;
|
||||
|
||||
# have we found openldap binaies suitable for setting up a server?
|
||||
my $ldap_binaries_found = $LdapServer::setup;
|
||||
|
||||
# create a server with the given root password and auth type
|
||||
# (users or anonymous)
|
||||
my $server = LdapServer->new($root_password, $auth_type);
|
||||
|
||||
# Add the contents of an LDIF file to the server
|
||||
$server->ldapadd_file ($path_to_ldif_data);
|
||||
|
||||
# set the Ldap password for a user
|
||||
$server->ldapsetpw($user, $password);
|
||||
|
||||
# get details of some settings for the server
|
||||
my @properties = $server->prop($propname1, $propname2, ...);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
LdapServer tests in its INIT phase for the presence of suitable openldap
|
||||
binaries. Its constructor method sets up and runs an LDAP server, and any
|
||||
servers that are set up are terminated during its END phase.
|
||||
|
||||
=cut
|
||||
|
||||
package LdapServer;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PostgreSQL::Test::Utils;
|
||||
use Test::More;
|
||||
|
||||
use File::Copy;
|
||||
use File::Basename;
|
||||
|
||||
# private variables
|
||||
my ($slapd, $ldap_schema_dir, @servers);
|
||||
|
||||
# visible variable
|
||||
our ($setup);
|
||||
|
||||
INIT
|
||||
{
|
||||
$setup = 1;
|
||||
if ($^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
|
||||
{
|
||||
$setup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
END
|
||||
{
|
||||
foreach my $server (@servers)
|
||||
{
|
||||
next unless -f $server->{pidfile};
|
||||
my $pid = slurp_file($server->{pidfile});
|
||||
chomp $pid;
|
||||
kill 'INT', $pid;
|
||||
}
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over
|
||||
|
||||
=item LdapServer->new($rootpw, $auth_type)
|
||||
|
||||
Create a new LDAP server.
|
||||
|
||||
The rootpw can be used when authenticating with the ldapbindpasswd option.
|
||||
|
||||
The auth_type is either 'users' or 'anonymous'.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub new
|
||||
{
|
||||
die "no suitable binaries found" unless $setup;
|
||||
|
||||
my $class = shift;
|
||||
my $rootpw = shift;
|
||||
my $authtype = shift; # 'users' or 'anonymous'
|
||||
my $testname = basename((caller)[1], '.pl');
|
||||
my $self = {};
|
||||
|
||||
my $test_temp = PostgreSQL::Test::Utils::tempdir("ldap-$testname");
|
||||
|
||||
my $ldap_datadir = "$test_temp/openldap-data";
|
||||
my $slapd_certs = "$test_temp/slapd-certs";
|
||||
my $slapd_pidfile = "$test_temp/slapd.pid";
|
||||
my $slapd_conf = "$test_temp/slapd.conf";
|
||||
my $slapd_logfile =
|
||||
"${PostgreSQL::Test::Utils::log_path}/slapd-$testname.log";
|
||||
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 = $rootpw;
|
||||
my $ldap_pwfile = "$test_temp/ldappassword";
|
||||
|
||||
(my $conf = <<"EOC") =~ s/^\t\t//gm;
|
||||
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 $authtype 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"
|
||||
EOC
|
||||
append_to_file($slapd_conf, $conf);
|
||||
|
||||
mkdir $ldap_datadir or die "making $ldap_datadir: $!";
|
||||
mkdir $slapd_certs or die "making $slapd_certs: $!";
|
||||
|
||||
my $certdir = dirname(__FILE__) . "/../ssl/ssl";
|
||||
|
||||
copy "$certdir/server_ca.crt", "$slapd_certs/ca.crt"
|
||||
|| die "copying ca.crt: $!";
|
||||
# check we actually have the file, as copy() sometimes gives a false success
|
||||
-f "$slapd_certs/ca.crt" || die "copying ca.crt (error unknown)";
|
||||
copy "$certdir/server-cn-only.crt", "$slapd_certs/server.crt"
|
||||
|| die "copying server.crt: $!";
|
||||
copy "$certdir/server-cn-only.key", "$slapd_certs/server.key"
|
||||
|| die "copying server.key: $!";
|
||||
|
||||
append_to_file($ldap_pwfile, $ldap_rootpw);
|
||||
chmod 0600, $ldap_pwfile or die "chmod on $ldap_pwfile";
|
||||
|
||||
system_or_bail $slapd, '-f', $slapd_conf, '-h', "$ldap_url $ldaps_url";
|
||||
|
||||
# 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);
|
||||
}
|
||||
|
||||
$self->{pidfile} = $slapd_pidfile;
|
||||
$self->{pwfile} = $ldap_pwfile;
|
||||
$self->{url} = $ldap_url;
|
||||
$self->{s_url} = $ldaps_url;
|
||||
$self->{server} = $ldap_server;
|
||||
$self->{port} = $ldap_port;
|
||||
$self->{s_port} = $ldaps_port;
|
||||
$self->{basedn} = $ldap_basedn;
|
||||
$self->{rootdn} = $ldap_rootdn;
|
||||
|
||||
bless $self, $class;
|
||||
push @servers, $self;
|
||||
return $self;
|
||||
}
|
||||
|
||||
# private routine to set up the environment for methods below
|
||||
sub _ldapenv
|
||||
{
|
||||
my $self = shift;
|
||||
my %env = %ENV;
|
||||
$env{'LDAPURI'} = $self->{url};
|
||||
$env{'LDAPBINDDN'} = $self->{rootdn};
|
||||
return %env;
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item ldap_add(filename)
|
||||
|
||||
filename is the path to a file containing LDIF data which is added to the LDAP
|
||||
server.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub ldapadd_file
|
||||
{
|
||||
my $self = shift;
|
||||
my $file = shift;
|
||||
|
||||
local %ENV = $self->_ldapenv;
|
||||
|
||||
system_or_bail 'ldapadd', '-x', '-y', $self->{pwfile}, '-f', $file;
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item ldapsetpw(user, password)
|
||||
|
||||
Set the user's password in the LDAP server
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub ldapsetpw
|
||||
{
|
||||
my $self = shift;
|
||||
my $user = shift;
|
||||
my $password = shift;
|
||||
|
||||
local %ENV = $self->_ldapenv;
|
||||
|
||||
system_or_bail 'ldappasswd', '-x', '-y', $self->{pwfile}, '-s', $password,
|
||||
$user;
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=over
|
||||
|
||||
=item prop(name1, ...)
|
||||
|
||||
Returns the list of values for the specified properties of the instance, such
|
||||
as 'url', 'port', 'basedn'.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub prop
|
||||
{
|
||||
my $self = shift;
|
||||
my @settings;
|
||||
push @settings, $self->{$_} foreach (@_);
|
||||
return @settings;
|
||||
}
|
||||
|
||||
1;
|
@ -3,170 +3,46 @@
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin;
|
||||
use lib "$FindBin::RealBin/..";
|
||||
|
||||
use File::Copy;
|
||||
use File::Basename;
|
||||
use LdapServer;
|
||||
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';
|
||||
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
|
||||
elsif (!$LdapServer::setup)
|
||||
{
|
||||
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 = '';
|
||||
note "setting up LDAP server";
|
||||
|
||||
$ENV{PATH} = "$ldap_bin_dir:$ENV{PATH}" if $ldap_bin_dir;
|
||||
my $ldap_rootpw = 'secret';
|
||||
my $ldap = LdapServer->new($ldap_rootpw, 'anonymous'); # use anonymous auth
|
||||
$ldap->ldapadd_file('authdata.ldif');
|
||||
$ldap->ldapsetpw('uid=test1,dc=example,dc=net', 'secret1');
|
||||
$ldap->ldapsetpw('uid=test2,dc=example,dc=net', 'secret2');
|
||||
|
||||
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";
|
||||
|
||||
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
|
||||
|
||||
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});
|
||||
my ($ldap_server, $ldap_port, $ldaps_port, $ldap_url,
|
||||
$ldaps_url, $ldap_basedn, $ldap_rootdn
|
||||
) = $ldap->prop(qw(server port s_port url s_url basedn rootdn));
|
||||
|
||||
# don't bother to check the server's cert (though perhaps we should)
|
||||
append_to_file(
|
||||
$ldap_conf,
|
||||
qq{TLS_REQCERT never
|
||||
});
|
||||
|
||||
mkdir $ldap_datadir or die;
|
||||
mkdir $slapd_certs or die;
|
||||
|
||||
# use existing certs from nearby SSL test suite
|
||||
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;
|
||||
|
||||
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';
|
||||
$ENV{'LDAPTLS_REQCERT'} = "never";
|
||||
|
||||
note "setting up PostgreSQL instance";
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user