to alter the owner, you must be able to <literal>SET ROLE</literal> to the
new owning role. If the subscription has
<literal>password_required=false</literal>, only superusers can modify it.
+ If the subscription uses a foreign server, the new owner must have
+ <literal>USAGE</literal> privilege on the foreign server, a user mapping
+ for the new owner or for <literal>PUBLIC</literal> must exist, and the
+ connection string generated for the new owner must be valid. If the new
+ owner is not a superuser and the subscription has
+ <literal>password_required=true</literal>, the generated connection string
+ must include a password.
</para>
<para>
/*
* If the subscription uses a server, check that the new owner has USAGE
- * privileges on the server and that a user mapping exists. Note: does not
- * re-check the resulting connection string.
+ * privileges on the server, that a user mapping exists, and that the
+ * resulting connection string is valid for the new owner.
*/
if (OidIsValid(form->subserver))
{
+ char *conninfo;
ForeignServer *server = GetForeignServer(form->subserver);
aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, newOwnerId, ACL_USAGE);
/* make sure a user mapping exists */
GetUserMapping(newOwnerId, server->serverid);
+
+ conninfo = ForeignServerConnectionString(newOwnerId, server);
+
+ /* Load the library providing us libpq calls. */
+ load_file("libpqwalreceiver", false);
+ /* Check the connection info string. */
+ walrcv_check_conninfo(conninfo,
+ form->subpasswordrequired &&
+ !superuser_arg(newOwnerId));
}
form->subowner = newOwnerId;
RETURNS text
AS :'regresslib', 'test_fdw_connection'
LANGUAGE C;
+CREATE FUNCTION test_fdw_connection_no_password(oid, oid, internal)
+ RETURNS text
+ AS :'regresslib', 'test_fdw_connection_no_password'
+ LANGUAGE C;
CREATE ROLE regress_subscription_user LOGIN SUPERUSER;
CREATE ROLE regress_subscription_user2;
CREATE ROLE regress_subscription_user3 IN ROLE pg_create_subscription;
WARNING: subscription was created, but is not connected
HINT: To initiate replication, you must manually create the replication slot, enable the subscription, and alter the subscription to refresh publications.
RESET SESSION AUTHORIZATION;
+GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user2;
+CREATE USER MAPPING FOR regress_subscription_user2 SERVER test_server OPTIONS(user 'foo');
+ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection_no_password;
+WARNING: changing the foreign-data wrapper connection function can cause the options for dependent objects to become invalid
+-- fail, new owner's generated conninfo must satisfy password_required
+ALTER SUBSCRIPTION regress_testsub6 OWNER TO regress_subscription_user2;
+ERROR: password is required
+DETAIL: Non-superusers must provide a password in the connection string.
+ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection;
+WARNING: changing the foreign-data wrapper connection function can cause the options for dependent objects to become invalid
+DROP USER MAPPING FOR regress_subscription_user2 SERVER test_server;
+REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user2;
REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user3;
SET SESSION AUTHORIZATION regress_subscription_user3;
-- ok, lacks USAGE on test_server, but replacing connection anyway
ALTER FOREIGN DATA WRAPPER test_fdw NO CONNECTION;
WARNING: removing the foreign-data wrapper connection function will cause dependent subscriptions to fail
DROP FUNCTION test_fdw_connection(oid, oid, internal);
+DROP FUNCTION test_fdw_connection_no_password(oid, oid, internal);
DROP FOREIGN DATA WRAPPER test_fdw;
-- fail - invalid connection string during ALTER
ALTER SUBSCRIPTION regress_testsub CONNECTION 'foobar';
PG_RETURN_TEXT_P(cstring_to_text("dbname=regress_doesnotexist user=doesnotexist password=secret"));
}
+PG_FUNCTION_INFO_V1(test_fdw_connection_no_password);
+Datum
+test_fdw_connection_no_password(PG_FUNCTION_ARGS)
+{
+ /* Ensure the test fails if no valid user mapping exists. */
+ GetUserMapping(PG_GETARG_OID(0), PG_GETARG_OID(1));
+ PG_RETURN_TEXT_P(cstring_to_text("dbname=regress_doesnotexist user=doesnotexist"));
+}
+
PG_FUNCTION_INFO_V1(is_catalog_text_unique_index_oid);
Datum
is_catalog_text_unique_index_oid(PG_FUNCTION_ARGS)
RETURNS text
AS :'regresslib', 'test_fdw_connection'
LANGUAGE C;
+CREATE FUNCTION test_fdw_connection_no_password(oid, oid, internal)
+ RETURNS text
+ AS :'regresslib', 'test_fdw_connection_no_password'
+ LANGUAGE C;
CREATE ROLE regress_subscription_user LOGIN SUPERUSER;
CREATE ROLE regress_subscription_user2;
PUBLICATION testpub WITH (slot_name = 'dummy', connect = false);
RESET SESSION AUTHORIZATION;
+GRANT USAGE ON FOREIGN SERVER test_server TO regress_subscription_user2;
+CREATE USER MAPPING FOR regress_subscription_user2 SERVER test_server OPTIONS(user 'foo');
+ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection_no_password;
+
+-- fail, new owner's generated conninfo must satisfy password_required
+ALTER SUBSCRIPTION regress_testsub6 OWNER TO regress_subscription_user2;
+
+ALTER FOREIGN DATA WRAPPER test_fdw CONNECTION test_fdw_connection;
+DROP USER MAPPING FOR regress_subscription_user2 SERVER test_server;
+REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user2;
+
REVOKE USAGE ON FOREIGN SERVER test_server FROM regress_subscription_user3;
SET SESSION AUTHORIZATION regress_subscription_user3;
ALTER FOREIGN DATA WRAPPER test_fdw NO CONNECTION;
DROP FUNCTION test_fdw_connection(oid, oid, internal);
+DROP FUNCTION test_fdw_connection_no_password(oid, oid, internal);
DROP FOREIGN DATA WRAPPER test_fdw;