Re: GSSENC'ed connection stalls while reconnection attempts. - Mailing list pgsql-hackers

From Tom Lane
Subject Re: GSSENC'ed connection stalls while reconnection attempts.
Date
Msg-id 2460502.1594510912@sss.pgh.pa.us
Whole thread Raw
In response to Re: GSSENC'ed connection stalls while reconnection attempts.  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
I wrote:
> Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
>> If psql connected using GSSAPI auth and server restarted, reconnection
>> sequence stalls and won't return.

> Yeah, reproduced here.  (I wonder if there's any reasonable way to
> exercise this scenario in src/test/kerberos/.)

I tried writing such a test based on the IO::Pty infrastructure used
by src/bin/psql/t/010_tab_completion.pl, as attached.  It works, but
it feels pretty grotty, especially seeing that so much of the patch
is copy-and-pasted from 010_tab_completion.pl.  I think if we want
to have a test like this, it'd be good to work a little harder on
refactoring so that more of that code can be shared.  My Perl skillz
are a bit weak for that, though.

            regards, tom lane

diff --git a/src/test/kerberos/t/001_auth.pl b/src/test/kerberos/t/001_auth.pl
index b3aeea9574..552d2724e7 100644
--- a/src/test/kerberos/t/001_auth.pl
+++ b/src/test/kerberos/t/001_auth.pl
@@ -13,17 +13,30 @@
 
 use strict;
 use warnings;
+
 use TestLib;
 use PostgresNode;
 use Test::More;
+use IPC::Run qw(pump finish timer);
+use Data::Dumper;
 
-if ($ENV{with_gssapi} eq 'yes')
+# Do nothing unless Makefile has told us that the build is --with-gssapi.
+if ($ENV{with_gssapi} ne 'yes')
 {
+    plan skip_all => 'GSSAPI/Kerberos not supported by this build';
+}
+
+# If we don't have IO::Pty, we can't run the test with interactive_psql.
+my $have_pty = 1;
+eval { require IO::Pty; };
+if ($@)
+{
+    $have_pty = 0;
     plan tests => 18;
 }
 else
 {
-    plan skip_all => 'GSSAPI/Kerberos not supported by this build';
+    plan tests => 22;
 }
 
 my ($krb5_bin_dir, $krb5_sbin_dir);
@@ -275,6 +288,77 @@ test_query(
     "gssencmode=require",
     "sending 100K lines works");
 
+# Test that libpq can reconnect after a server restart.
+if ($have_pty)
+{
+    # fire up an interactive psql session
+    my $in  = '';
+    my $out = '';
+
+    my $timer = timer(5);
+
+    my $h = $node->interactive_psql(
+        'postgres',
+        \$in,
+        \$out,
+        $timer,
+        extra_params => [
+            '-XAtd',
+            $node->connstr('postgres')
+              . " host=$host hostaddr=$hostaddr gssencmode=require user=test1"
+        ]);
+
+    like(
+        $out,
+        qr/GSSAPI-encrypted connection/,
+        "startup banner shows GSSAPI encryption");
+
+    # subroutine to send a command and wait for response
+    sub interactive_command
+    {
+        my ($send, $pattern, $annotation) = @_;
+
+        # report test failures from caller location
+        local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+        # reset output collector
+        $out = "";
+        # restart per-command timer
+        $timer->start(5);
+        # send the data to be sent
+        $in .= $send;
+        # wait ...
+        pump $h until ($out =~ $pattern || $timer->is_expired);
+        my $okay = ($out =~ $pattern && !$timer->is_expired);
+        ok($okay, $annotation);
+        # for debugging, log actual output if it didn't match
+        local $Data::Dumper::Terse = 1;
+        local $Data::Dumper::Useqq = 1;
+        diag 'Actual output was '
+          . Dumper($out)
+          . "Did not match \"$pattern\"\n"
+          if !$okay;
+        return;
+    }
+
+    interactive_command("SELECT 2+2;\n", qr/4/, "interactive psql is alive");
+
+    $node->restart;
+
+    interactive_command(
+        "SELECT 2+2;\n",
+        qr/The connection to the server was lost.*GSSAPI-encrypted connection/s,
+        "startup banner shows GSSAPI encryption after reconnection");
+
+    interactive_command("SELECT 20+22;\n", qr/42/, "psql is still alive");
+
+    # send psql an explicit \q to shut it down, else pty won't close properly
+    $timer->start(5);
+    $in .= "\\q\n";
+    finish $h or die "psql returned $?";
+    $timer->reset;
+}
+
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
     qq{hostgssenc all all $hostaddr/32 gss map=mymap});

pgsql-hackers by date:

Previous
From: Tomas Vondra
Date:
Subject: Re: WIP: BRIN multi-range indexes
Next
From: Peter Geoghegan
Date:
Subject: Re: Default setting for enable_hashagg_disk