Skip to content

Commit 5c31669

Browse files
committed
Re-validate connection string in libpqrcv_connect().
A superuser may create a subscription with password_required=true, but which uses a connection string without a password. Previously, if the owner of such a subscription was changed to a non-superuser, the non-superuser was able to utilize a password from another source (like a password file or the PGPASSWORD environment variable), which should not have been allowed. This commit adds a step to re-validate the connection string before connecting. Reported-by: Jeff Davis Author: Vignesh C Reviewed-by: Peter Smith, Robert Haas, Amit Kapila Discussion: https://www.postgresql.org/message-id/flat/e5892973ae2a80a1a3e0266806640dae3c428100.camel%40j-davis.com Backpatch-through: 16
1 parent a160423 commit 5c31669

File tree

3 files changed

+95
-5
lines changed

3 files changed

+95
-5
lines changed

doc/src/sgml/ref/create_subscription.sgml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,11 +357,12 @@ CREATE SUBSCRIPTION <replaceable class="parameter">subscription_name</replaceabl
357357
<term><literal>password_required</literal> (<type>boolean</type>)</term>
358358
<listitem>
359359
<para>
360-
Specifies whether connections to the publisher made as a result
361-
of this subscription must use password authentication. This setting
362-
is ignored when the subscription is owned by a superuser.
363-
The default is <literal>true</literal>. Only superusers can set
364-
this value to <literal>false</literal>.
360+
If set to <literal>true</literal>, connections to the publisher made
361+
as a result of this subscription must use password authentication
362+
and the password must be specified as a part of the connection
363+
string. This setting is ignored when the subscription is owned by a
364+
superuser. The default is <literal>true</literal>. Only superusers
365+
can set this value to <literal>false</literal>.
365366
</para>
366367
</listitem>
367368
</varlistentry>

src/backend/replication/libpqwalreceiver/libpqwalreceiver.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,15 @@ libpqrcv_connect(const char *conninfo, bool logical, bool must_use_password,
137137
const char *vals[6];
138138
int i = 0;
139139

140+
/*
141+
* Re-validate connection string. The validation already happened at DDL
142+
* time, but the subscription owner may have changed. If we don't recheck
143+
* with the correct must_use_password, it's possible that the connection
144+
* will obtain the password from a different source, such as PGPASSFILE or
145+
* PGPASSWORD.
146+
*/
147+
libpqrcv_check_conninfo(conninfo, must_use_password);
148+
140149
/*
141150
* We use the expand_dbname parameter to process the connection string (or
142151
* URI), and pass some extra options.

src/test/subscription/t/027_nosuperuser.pl

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,4 +327,84 @@ sub grant_superuser
327327
qr/LOG: ( [A-Z0-9]+:)? logical replication worker for subscription \"regression_sub\" will restart because the subscription owner's superuser privileges have been revoked/,
328328
$offset);
329329

330+
# If the subscription connection requires a password ('password_required'
331+
# is true) then a non-superuser must specify that password in the connection
332+
# string.
333+
$ENV{"PGPASSWORD"} = 'secret';
334+
335+
my $node_publisher1 = PostgreSQL::Test::Cluster->new('publisher1');
336+
my $node_subscriber1 = PostgreSQL::Test::Cluster->new('subscriber1');
337+
$node_publisher1->init(allows_streaming => 'logical');
338+
$node_subscriber1->init;
339+
$node_publisher1->start;
340+
$node_subscriber1->start;
341+
my $publisher_connstr1 =
342+
$node_publisher1->connstr . ' user=regress_test_user dbname=postgres';
343+
my $publisher_connstr2 =
344+
$node_publisher1->connstr
345+
. ' user=regress_test_user dbname=postgres password=secret';
346+
347+
for my $node ($node_publisher1, $node_subscriber1)
348+
{
349+
$node->safe_psql(
350+
'postgres', qq(
351+
CREATE ROLE regress_test_user PASSWORD 'secret' LOGIN REPLICATION;
352+
GRANT CREATE ON DATABASE postgres TO regress_test_user;
353+
GRANT PG_CREATE_SUBSCRIPTION TO regress_test_user;
354+
));
355+
}
356+
357+
$node_publisher1->safe_psql(
358+
'postgres', qq(
359+
SET SESSION AUTHORIZATION regress_test_user;
360+
CREATE PUBLICATION regress_test_pub;
361+
));
362+
$node_subscriber1->safe_psql(
363+
'postgres', qq(
364+
CREATE SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr1' PUBLICATION regress_test_pub;
365+
));
366+
367+
# Wait for initial sync to finish
368+
$node_subscriber1->wait_for_subscription_sync($node_publisher1,
369+
'regress_test_sub');
370+
371+
# Setup pg_hba configuration so that logical replication connection without
372+
# password is not allowed.
373+
unlink($node_publisher1->data_dir . '/pg_hba.conf');
374+
$node_publisher1->append_conf('pg_hba.conf',
375+
qq{local all regress_test_user md5});
376+
$node_publisher1->reload;
377+
378+
# Change the subscription owner to a non-superuser
379+
$node_subscriber1->safe_psql(
380+
'postgres', qq(
381+
ALTER SUBSCRIPTION regress_test_sub OWNER TO regress_test_user;
382+
));
383+
384+
# Non-superuser must specify password in the connection string
385+
my ($ret, $stdout, $stderr) = $node_subscriber1->psql(
386+
'postgres', qq(
387+
SET SESSION AUTHORIZATION regress_test_user;
388+
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
389+
));
390+
isnt($ret, 0,
391+
"non zero exit for subscription whose owner is a non-superuser must specify password parameter of the connection string"
392+
);
393+
ok( $stderr =~ m/DETAIL: Non-superusers must provide a password in the connection string./,
394+
'subscription whose owner is a non-superuser must specify password parameter of the connection string'
395+
);
396+
397+
delete $ENV{"PGPASSWORD"};
398+
399+
# It should succeed after including the password parameter of the connection
400+
# string.
401+
($ret, $stdout, $stderr) = $node_subscriber1->psql(
402+
'postgres', qq(
403+
SET SESSION AUTHORIZATION regress_test_user;
404+
ALTER SUBSCRIPTION regress_test_sub CONNECTION '$publisher_connstr2';
405+
ALTER SUBSCRIPTION regress_test_sub REFRESH PUBLICATION;
406+
));
407+
is($ret, 0,
408+
"Non-superuser will be able to refresh the publication after specifying the password parameter of the connection string"
409+
);
330410
done_testing();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy