Here is a patch with a test suite for the Kerberos/GSSAPI authentication
functionality.  It's very similar in principle to the recently added
LDAP tests, and similar caveats apply.

You will need the client and server parts of a krb5 package
installation, possibly named krb5-workstation and krb5-server, or
perhaps krb5-user and krb5-kdc.

(If it appears to hang for you in the "setting up Kerberos" step, you
might need more entropy/wait a while.  That problem appears to be
limited to some virtual machine setups, but the specifics are not clear.)

-- 
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From 108530921d7a3780cd5d1a31aebadd29621de429 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pete...@gmx.net>
Date: Wed, 14 Feb 2018 09:10:50 -0500
Subject: [PATCH] Tests for Kerberos/GSSAPI authentication

---
 configure                       |   2 +
 configure.in                    |   1 +
 src/Makefile.global.in          |   1 +
 src/test/kerberos/.gitignore    |   2 +
 src/test/kerberos/Makefile      |  25 +++++++
 src/test/kerberos/README        |  25 +++++++
 src/test/kerberos/t/001_auth.pl | 143 ++++++++++++++++++++++++++++++++++++++++
 src/test/perl/PostgresNode.pm   |   8 ++-
 8 files changed, 205 insertions(+), 2 deletions(-)
 create mode 100644 src/test/kerberos/.gitignore
 create mode 100644 src/test/kerberos/Makefile
 create mode 100644 src/test/kerberos/README
 create mode 100644 src/test/kerberos/t/001_auth.pl

diff --git a/configure b/configure
index 7dcca506f8..84b547be79 100755
--- a/configure
+++ b/configure
@@ -708,6 +708,7 @@ with_uuid
 with_systemd
 with_selinux
 with_openssl
+with_krb_srvnam
 krb_srvtab
 with_python
 with_perl
@@ -5814,6 +5815,7 @@ fi
 
 
 
+
 cat >>confdefs.h <<_ACEOF
 #define PG_KRB_SRVNAM "$with_krb_srvnam"
 _ACEOF
diff --git a/configure.in b/configure.in
index 4d26034579..dbd7fa2c48 100644
--- a/configure.in
+++ b/configure.in
@@ -650,6 +650,7 @@ PGAC_ARG_REQ(with, krb-srvnam,
              [NAME], [default service principal name in Kerberos (GSSAPI) 
[postgres]],
              [],
              [with_krb_srvnam="postgres"])
+AC_SUBST(with_krb_srvnam)
 AC_DEFINE_UNQUOTED([PG_KRB_SRVNAM], ["$with_krb_srvnam"],
                    [Define to the name of the default PostgreSQL service 
principal in Kerberos (GSSAPI). (--with-krb-srvnam=NAME)])
 
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index d980f81046..1c6c0d3eea 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -188,6 +188,7 @@ with_selinux        = @with_selinux@
 with_systemd   = @with_systemd@
 with_libxml    = @with_libxml@
 with_libxslt   = @with_libxslt@
+with_krb_srvnam        = @with_krb_srvnam@
 with_system_tzdata = @with_system_tzdata@
 with_uuid      = @with_uuid@
 with_zlib      = @with_zlib@
diff --git a/src/test/kerberos/.gitignore b/src/test/kerberos/.gitignore
new file mode 100644
index 0000000000..871e943d50
--- /dev/null
+++ b/src/test/kerberos/.gitignore
@@ -0,0 +1,2 @@
+# Generated by test suite
+/tmp_check/
diff --git a/src/test/kerberos/Makefile b/src/test/kerberos/Makefile
new file mode 100644
index 0000000000..1363529498
--- /dev/null
+++ b/src/test/kerberos/Makefile
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/test/kerberos
+#
+# Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/test/kerberos/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/test/kerberos
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+export with_krb_srvnam
+
+check:
+       $(prove_check)
+
+installcheck:
+       $(prove_installcheck)
+
+clean distclean maintainer-clean:
+       rm -rf tmp_check
diff --git a/src/test/kerberos/README b/src/test/kerberos/README
new file mode 100644
index 0000000000..94cf7ff42e
--- /dev/null
+++ b/src/test/kerberos/README
@@ -0,0 +1,25 @@
+src/test/kerberos/README
+
+Tests for Kerberos/GSSAPI functionality
+=======================================
+
+This directory contains a test suite for Kerberos/GSSAPI
+functionality.  This requires a full MIT Kerberos 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 MIT Kerberos in a place that hadn't been thought
+of yet.
+
+Also, this test suite creates a KDC 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
+
+or
+
+    make installcheck
diff --git a/src/test/kerberos/t/001_auth.pl b/src/test/kerberos/t/001_auth.pl
new file mode 100644
index 0000000000..5d6f3df8bf
--- /dev/null
+++ b/src/test/kerberos/t/001_auth.pl
@@ -0,0 +1,143 @@
+use strict;
+use warnings;
+use TestLib;
+use PostgresNode;
+use Test::More tests => 4;
+
+my ($krb5_bin_dir, $krb5_sbin_dir);
+
+if ($^O eq 'darwin')
+{
+       $krb5_bin_dir = '/usr/local/opt/krb5/bin';
+       $krb5_sbin_dir = '/usr/local/opt/krb5/sbin';
+}
+elsif ($^O eq 'linux')
+{
+       $krb5_sbin_dir = '/usr/sbin';
+}
+
+$ENV{PATH} = "$krb5_sbin_dir:$ENV{PATH}" if $krb5_sbin_dir;
+$ENV{PATH} = "$krb5_bin_dir:$ENV{PATH}" if $krb5_bin_dir;
+
+my $realm = 'EXAMPLE.COM';
+
+my $krb5_conf = "${TestLib::tmp_check}/krb5.conf";
+my $kdc_conf = "${TestLib::tmp_check}/kdc.conf";
+my $krb5_log = "${TestLib::tmp_check}/krb5libs.log";
+my $kdc_log = "${TestLib::tmp_check}/krb5kdc.log";
+my $kdc_port = int(rand() * 16384) + 49152;
+my $kdc_datadir = "${TestLib::tmp_check}/krb5kdc";
+my $kdc_pidfile = "${TestLib::tmp_check}/krb5kdc.pid";
+my $keytab = "${TestLib::tmp_check}/krb5.keytab";
+
+note "setting up Kerberos";
+
+my ($stdout, $krb5_version);
+IPC::Run::run [ 'krb5-config', '--version' ], '>', \$stdout or die "could not 
execute krb5-config";
+$stdout =~ m/Kerberos 5 release ([0-9]+\.[0-9]+)/ or die "could not get 
Kerberos version";
+$krb5_version = $1;
+
+append_to_file($krb5_conf,
+qq![logging]
+default = FILE:$krb5_log
+kdc = FILE:$kdc_log
+
+[libdefaults]
+default_realm = $realm
+
+[realms]
+$realm = {
+    kdc = localhost:$kdc_port
+}!);
+
+append_to_file($kdc_conf,
+qq![kdcdefaults]
+!);
+# For new-enough versions of krb5, use the _listen settings rather
+# than the _ports settings so that we can bind to localhost only.
+if ($krb5_version >= 1.15)
+{
+       append_to_file($kdc_conf,
+qq!kdc_listen = localhost:$kdc_port
+kdc_tcp_listen = localhost:$kdc_port
+!);
+}
+else
+{
+       append_to_file($kdc_conf,
+qq!kdc_ports = $kdc_port
+kdc_tcp_ports = $kdc_port
+!);
+}
+append_to_file($kdc_conf,
+qq!
+[realms]
+$realm = {
+    database_name = $kdc_datadir/principal
+    admin_keytab = FILE:$kdc_datadir/kadm5.keytab
+    acl_file = $kdc_datadir/kadm5.acl
+    key_stash_file = $kdc_datadir/_k5.$realm
+}!);
+
+mkdir $kdc_datadir or die;
+
+$ENV{'KRB5_CONFIG'} = $krb5_conf;
+$ENV{'KRB5_KDC_PROFILE'} = $kdc_conf;
+
+my $service_principal = "$ENV{with_krb_srvnam}/localhost";
+
+system_or_bail 'kdb5_util', 'create', '-s', '-P', 'secret0';
+
+system_or_bail 'kadmin.local', '-q', "addprinc -pw secret1 test1";
+
+system_or_bail 'kadmin.local', '-q', "addprinc -randkey $service_principal";
+system_or_bail 'kadmin.local', '-q', "ktadd -k $keytab $service_principal";
+
+system_or_bail 'krb5kdc', '-P', $kdc_pidfile;
+
+END
+{
+    kill 'INT', `cat $kdc_pidfile` if -f $kdc_pidfile;
+}
+
+note "setting up PostgreSQL instance";
+
+my $node = get_new_node('node');
+$node->init;
+$node->append_conf('postgresql.conf', "listen_addresses = 'localhost'");
+$node->append_conf('postgresql.conf', "krb_server_keyfile = '$keytab'");
+$node->start;
+
+$node->safe_psql('postgres', 'CREATE USER test1;');
+
+note "running tests";
+
+sub test_access
+{
+    my ($node, $role, $expected_res, $test_name) = @_;
+
+    my $res = $node->psql('postgres', 'SELECT 1', tcpip => 1, extra_params => 
[ '-U', $role ]);
+    is($res, $expected_res, $test_name);
+}
+
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{host all all localhost gss map=mymap});
+$node->restart;
+
+test_access($node, 'test1', 2, 'fails without ticket');
+
+system_or_bail 'echo secret1 | kinit test1';
+
+test_access($node, 'test1', 2, 'fails without mapping');
+
+$node->append_conf('pg_ident.conf', qq{mymap  /^(.*)\@$realm\$  \\1});
+$node->restart;
+
+test_access($node, 'test1', 0, 'succeeds with mapping');
+
+truncate($node->data_dir . '/pg_ident.conf', 0);
+unlink($node->data_dir . '/pg_hba.conf');
+$node->append_conf('pg_hba.conf', qq{host all all localhost gss 
include_realm=0});
+$node->restart;
+
+test_access($node, 'test1', 0, 'succeeds with include_realm=0');
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 1d5ac4ee35..fcc6de3671 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -1129,8 +1129,7 @@ sub psql
        my $stderr            = $params{stderr};
        my $timeout           = undef;
        my $timeout_exception = 'psql timed out';
-       my @psql_params =
-         ('psql', '-XAtq', '-d', $self->connstr($dbname), '-f', '-');
+       my $connstr           = $self->connstr($dbname);
 
        # If the caller wants an array and hasn't passed stdout/stderr
        # references, allocate temporary ones to capture them so we
@@ -1152,6 +1151,11 @@ sub psql
        $params{on_error_stop} = 1 unless defined $params{on_error_stop};
        $params{on_error_die}  = 0 unless defined $params{on_error_die};
 
+       $connstr .= ' host=localhost' if defined $params{tcpip};
+
+       my @psql_params =
+         ('psql', '-XAtq', '-d', $connstr, '-f', '-');
+
        push @psql_params, '-v', 'ON_ERROR_STOP=1' if $params{on_error_stop};
        push @psql_params, @{ $params{extra_params} }
          if defined $params{extra_params};
-- 
2.16.1

Reply via email to