# # Exercises the API for custom OAuth client flows, using the oauth_hook_client # test driver. # # Copyright (c) 2021-2025, PostgreSQL Global Development Group #
use strict;
use warnings FATAL => 'all';
use JSON::PP qw(encode_json);
use MIME::Base64 qw(encode_base64);
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
if (!$ENV{PG_TEST_EXTRA} || $ENV{PG_TEST_EXTRA} !~ /\boauth\b/)
{
plan skip_all => 'Potentially unsafe test oauth not enabled in PG_TEST_EXTRA';
}
# # Cluster Setup #
my $node = PostgreSQL::Test::Cluster->new('primary');
$node->init;
$node->append_conf('postgresql.conf', "log_connections = all\n");
$node->append_conf('postgresql.conf', "oauth_validator_libraries = 'validator'\n"); # Needed to inspect postmaster log after connection failure:
$node->append_conf('postgresql.conf', "log_min_messages = debug2");
$node->start;
$node->safe_psql('postgres', 'CREATE USER test;');
# These tests don't use the builtin flow, and we don't have an authorization # server running, so the address used here shouldn't matter. Use an invalid IP # address, so if there's some cascade of errors that causes the client to # attempt a connection, we'll fail noisily.
my $issuer = "https://256.256.256.256";
my $scope = "openid postgres";
unlink($node->data_dir . '/pg_hba.conf');
$node->append_conf( 'pg_hba.conf', qq{
local all test oauth issuer="$issuer" scope="$scope"
});
$node->reload;
my $log_start = -s $node->logfile;
my ($stdout, $stderr) = run_command(\@cmd);
if (defined($params{expected_stdout}))
{
like($stdout, $params{expected_stdout}, "$test_name: stdout matches");
}
if (defined($params{expected_stderr}))
{
like($stderr, $params{expected_stderr}, "$test_name: stderr matches");
} else
{
is($stderr, "", "$test_name: no stderr");
}
if (defined($params{log_like}))
{ # See Cluster::connect_fails(). To avoid races, we have to wait for the # postmaster to flush the log for the finished connection.
$node->wait_for_log(
qr/DEBUG: (?:00000: )?forked new client backend, pid=(\d+) socket.*DEBUG: (?:00000: )?client backend \(PID \1\) exited with exit code \d/s,
$log_start);
test( "basic synchronous hook can provide a token",
flags => [ "--token", "my-token", "--expected-uri", "$issuer/.well-known/openid-configuration", "--expected-scope", $scope,
],
expected_stdout => qr/connection succeeded/,
log_like => [qr/oauth_validator: token="my-token", role="$user"/]);
if ($ENV{with_libcurl} ne 'yes')
{ # libpq should help users out if no OAuth support is built in.
test( "fails without custom hook installed",
flags => ["--no-hook"],
expected_stderr =>
qr/no OAuth flows are available \(try installing the libpq-oauth package\)/
);
}
# connect_timeout should work if the flow doesn't respond.
$common_connstr = "$common_connstr connect_timeout=1";
test( "connect_timeout interrupts hung client flow",
flags => ["--hang-forever"],
expected_stderr => qr/failed: timeout expired/);
# Remove the timeout for later tests.
$common_connstr = "$base_connstr oauth_issuer=$issuer oauth_client_id=myID";
# Test various misbehaviors of the client hook.
my @cases = (
{
flag => "--misbehave=no-hook",
expected_error =>
qr/user-defined OAuth flow provided neither a token nor an async callback/,
},
{
flag => "--misbehave=fail-async",
expected_error => qr/user-defined OAuth flow failed/,
},
{
flag => "--misbehave=no-token",
expected_error => qr/user-defined OAuth flow did not provide a token/,
},
{
flag => "--misbehave=no-socket",
expected_error =>
qr/user-defined OAuth flow did not provide a socket for polling/,
});
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.