* Adds granted roles filter for non-distributed roles

* Adds a sync filter for metadata sync
granted_by_propagation
gurkanindibay 2024-03-11 11:05:35 +03:00
parent 7a7c41f819
commit 580bbd5570
4 changed files with 565 additions and 73 deletions

View File

@ -56,6 +56,13 @@
#include "distributed/version_compat.h" #include "distributed/version_compat.h"
#include "distributed/worker_transaction.h" #include "distributed/worker_transaction.h"
typedef struct DistributedRolesInGrantRoleStmt
{
List *distributedGrantees;
List *distributedGrantedRoles;
RoleSpec *grantor;
bool isGrantRoleStmtValid;
} DistributedRolesInGrantRoleStmt;
static const char * ExtractEncryptedPassword(Oid roleOid); static const char * ExtractEncryptedPassword(Oid roleOid);
static const char * CreateAlterRoleIfExistsCommand(AlterRoleStmt *stmt); static const char * CreateAlterRoleIfExistsCommand(AlterRoleStmt *stmt);
@ -68,6 +75,7 @@ static DefElem * makeDefElemBool(char *name, bool value);
static List * GenerateRoleOptionsList(HeapTuple tuple); static List * GenerateRoleOptionsList(HeapTuple tuple);
static List * GenerateGrantRoleStmtsFromOptions(RoleSpec *roleSpec, List *options); static List * GenerateGrantRoleStmtsFromOptions(RoleSpec *roleSpec, List *options);
static List * GenerateGrantRoleStmtsOfRole(Oid roleid); static List * GenerateGrantRoleStmtsOfRole(Oid roleid);
static ObjectAddress * GetRoleObjectAddressFromOid(Oid roleOid);
static GrantRoleStmt * GetGrantRoleStmtFromAuthMemberRecord(Form_pg_auth_members static GrantRoleStmt * GetGrantRoleStmtFromAuthMemberRecord(Form_pg_auth_members
membership); membership);
static List * GenerateSecLabelOnRoleStmts(Oid roleid, char *rolename); static List * GenerateSecLabelOnRoleStmts(Oid roleid, char *rolename);
@ -937,6 +945,29 @@ GenerateGrantRoleStmts()
{ {
Form_pg_auth_members membership = (Form_pg_auth_members) GETSTRUCT(tuple); Form_pg_auth_members membership = (Form_pg_auth_members) GETSTRUCT(tuple);
/* we only propagate the grant if the grantor is
* member and role are distributed since all are required
* to be distributed for the grant to be propagated
*/
bool isAuthMemberDistributed = IsAnyObjectDistributed(list_make1(
GetRoleObjectAddressFromOid(
membership->grantor)))
&&
IsAnyObjectDistributed(list_make1(
GetRoleObjectAddressFromOid(
membership->member)))
&&
IsAnyObjectDistributed(list_make1(
GetRoleObjectAddressFromOid(
membership->roleid)));
if (!isAuthMemberDistributed)
{
/* we only need to propagate the grant if the grantor is distributed */
continue;
}
GrantRoleStmt *grantRoleStmt = GetGrantRoleStmtFromAuthMemberRecord(membership); GrantRoleStmt *grantRoleStmt = GetGrantRoleStmtFromAuthMemberRecord(membership);
if (grantRoleStmt == NULL) if (grantRoleStmt == NULL)
{ {
@ -972,6 +1003,15 @@ GenerateGrantRoleStmts()
} }
static ObjectAddress *
GetRoleObjectAddressFromOid(Oid roleOid)
{
ObjectAddress *roleAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*roleAddress, AuthIdRelationId, roleOid);
return roleAddress;
}
static GrantRoleStmt * static GrantRoleStmt *
GetGrantRoleStmtFromAuthMemberRecord(Form_pg_auth_members membership) GetGrantRoleStmtFromAuthMemberRecord(Form_pg_auth_members membership)
{ {
@ -1310,6 +1350,38 @@ FilterDistributedRoles(List *roles)
} }
/*
* FilterDistributedRoles filters the list of AccessPrivs and returns the ones
* that are distributed.
*/
List *
FilterDistributedGrantedRoles(List *roles)
{
List *distributedRoles = NIL;
Node *roleNode = NULL;
foreach_ptr(roleNode, roles)
{
AccessPriv *role = castNode(AccessPriv, roleNode);
Oid roleOid = get_role_oid(role->priv_name, false);
if (roleOid == InvalidOid)
{
/*
* Non-existing roles are ignored silently here. Postgres will
* handle to give an error or not for these roles.
*/
continue;
}
ObjectAddress *roleAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*roleAddress, AuthIdRelationId, roleOid);
if (IsAnyObjectDistributed(list_make1(roleAddress)))
{
distributedRoles = lappend(distributedRoles, role);
}
}
return distributedRoles;
}
/* /*
* PreprocessGrantRoleStmt finds the distributed grantee roles and creates the * PreprocessGrantRoleStmt finds the distributed grantee roles and creates the
* query to run on the workers. * query to run on the workers.
@ -1327,17 +1399,22 @@ PreprocessGrantRoleStmt(Node *node, const char *queryString,
GrantRoleStmt *stmt = castNode(GrantRoleStmt, node); GrantRoleStmt *stmt = castNode(GrantRoleStmt, node);
List *allGranteeRoles = stmt->grantee_roles; List *allGranteeRoles = stmt->grantee_roles;
List *allGrantedRoles = stmt->granted_roles;
RoleSpec *grantor = stmt->grantor; RoleSpec *grantor = stmt->grantor;
List *distributedGranteeRoles = FilterDistributedRoles(allGranteeRoles); DistributedRolesInGrantRoleStmt *distributedRolesInGrantStmt =
if (list_length(distributedGranteeRoles) <= 0) ExtractDistributedRolesInGrantRoleStmt(stmt);
if (!distributedRolesInGrantStmt->isGrantRoleStmtValid)
{ {
return NIL; return NIL;
} }
stmt->grantee_roles = distributedGranteeRoles; stmt->grantee_roles = distributedRolesInGrantStmt->distributedGrantees;
stmt->granted_roles = distributedRolesInGrantStmt->distributedGrantedRoles;
char *sql = DeparseTreeNode((Node *) stmt); char *sql = DeparseTreeNode((Node *) stmt);
stmt->grantee_roles = allGranteeRoles; stmt->grantee_roles = allGranteeRoles;
stmt->granted_roles = allGrantedRoles;
stmt->grantor = grantor; stmt->grantor = grantor;
List *commands = list_make3(DISABLE_DDL_PROPAGATION, List *commands = list_make3(DISABLE_DDL_PROPAGATION,
@ -1348,6 +1425,55 @@ PreprocessGrantRoleStmt(Node *node, const char *queryString,
} }
DistributedRolesInGrantRoleStmt *
ExtractDistributedRolesInGrantRoleStmt(GrantRoleStmt *stmt)
{
DistributedRolesInGrantRoleStmt *distributedRolesInGrantRoleStmt = palloc0(
sizeof(DistributedRolesInGrantRoleStmt));
distributedRolesInGrantRoleStmt->distributedGrantees = FilterDistributedRoles(
stmt->grantee_roles);
distributedRolesInGrantRoleStmt->distributedGrantedRoles =
FilterDistributedGrantedRoles(stmt->granted_roles);
distributedRolesInGrantRoleStmt->grantor = stmt->grantor;
distributedRolesInGrantRoleStmt->isGrantRoleStmtValid = true;
bool grantorMissingOk = false;
bool isGrantorDefined = distributedRolesInGrantRoleStmt->grantor != NULL &&
get_rolespec_oid(distributedRolesInGrantRoleStmt->grantor,
grantorMissingOk) !=
InvalidOid;
bool isGrantorDistributed = IsAnyObjectDistributed(RoleSpecToObjectAddress(
distributedRolesInGrantRoleStmt
->grantor, grantorMissingOk));
bool skipDueToGrantor = isGrantorDefined && !isGrantorDistributed;
if (list_length(distributedRolesInGrantRoleStmt->distributedGrantees) <= 0)
{
ereport(NOTICE, (errmsg("not propagating GRANT command to other nodes"),
errhint("Since no grantees are distributed, "
"the GRANT command will not be propagated to other nodes.")));
distributedRolesInGrantRoleStmt->isGrantRoleStmtValid = false;
}
if (list_length(distributedRolesInGrantRoleStmt->distributedGrantedRoles) <= 0)
{
ereport(NOTICE, (errmsg("not propagating GRANT command to other nodes"),
errhint("Since no granted roles are distributed, "
"the GRANT command will not be propagated to other nodes.")));
distributedRolesInGrantRoleStmt->isGrantRoleStmtValid = false;
}
if (skipDueToGrantor)
{
ereport(NOTICE, (errmsg("not propagating GRANT command to other nodes"),
errhint("Since grantor is not distributed, "
"the GRANT command will not be propagated to other nodes.")));
distributedRolesInGrantRoleStmt->isGrantRoleStmtValid = false;
}
return distributedRolesInGrantRoleStmt;
}
/* /*
* PostprocessGrantRoleStmt actually creates the plan we need to execute for grant * PostprocessGrantRoleStmt actually creates the plan we need to execute for grant
* role statement. * role statement.

View File

@ -523,7 +523,10 @@ extern List * RenameRoleStmtObjectAddress(Node *stmt, bool missing_ok, bool
isPostprocess); isPostprocess);
extern void UnmarkRolesDistributed(List *roles); extern void UnmarkRolesDistributed(List *roles);
extern List * FilterDistributedGrantedRoles(List *roles);
extern List * FilterDistributedRoles(List *roles); extern List * FilterDistributedRoles(List *roles);
extern DistributedRolesInGrantRoleStmt * ExtractDistributedRolesInGrantRoleStmt(
GrantRoleStmt *stmt);
extern List * GenerateGrantRoleStmts(void); extern List * GenerateGrantRoleStmts(void);
/* schema.c - forward declarations */ /* schema.c - forward declarations */

View File

@ -1,47 +1,68 @@
-- Active: 1700033167033@@localhost@9700@gurkanindibay@public -- Active: 1700033167033@@localhost@9700@gurkanindibay@public
--In below tests, complex role hierarchy is created and then granted by support is tested. --In below tests, complex role hierarchy is created and then granted by support is tested.
--- Test 1: Tests from main database
select 1 from citus_remove_node ('localhost',:worker_2_port); select 1 from citus_remove_node ('localhost',:worker_2_port);
?column? ?column?
--------------------------------------------------------------------- ---------------------------------------------------------------------
1 1
(1 row) (1 row)
create role role1; set citus.enable_create_role_propagation to off;
create role role2; create role non_dist_role1;
create role role3; NOTICE: not propagating CREATE ROLE/USER commands to other nodes
create role role4; HINT: Connect to other nodes directly to manually create all necessary users and roles.
create role "role5'_test"; reset citus.enable_create_role_propagation;
grant role2 to role1 with admin option; select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
grant role2 to role3 with admin option granted by role1; rolname
grant role3 to role4 with admin option;
grant role3 to "role5'_test" granted by role4;
grant role2 to "role5'_test" granted by role3;
grant role4 to "role5'_test" with admin option;
grant role4 to role1 with admin option GRANTED BY "role5'_test";
grant role4 to role3 with admin option GRANTED BY role1;
ERROR: role "role4" is a member of role "role3"
grant role3 to role1 with admin option GRANTED BY role4;
grant "role5'_test" to role1 with admin option;
grant "role5'_test" to role3 with admin option GRANTED BY role1;
ERROR: role "role5'_test" is a member of role "role3"
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text;
member | role | grantor | admin_option
--------------------------------------------------------------------- ---------------------------------------------------------------------
"role5'_test" | role2 | role3 | f (0 rows)
"role5'_test" | role3 | role4 | f
"role5'_test" | role4 | postgres | t
role1 | "role5'_test" | postgres | t
role1 | role2 | postgres | t
role1 | role3 | role4 | t
role1 | role4 | "role5'_test" | t
role3 | role2 | role1 | t
role4 | role3 | postgres | t
(9 rows)
create role dist_role1;
create role dist_role2;
create role dist_role3;
create role dist_role4;
create role "dist_role5'_test";
grant dist_role2 to dist_role1 with admin option;
grant dist_role2 to dist_role3 with admin option granted by dist_role1;
grant dist_role3 to dist_role4 with admin option;
-- With enable_create_role_propagation on, all grantees are propagated.
-- To test non-distributed grantor, set this option off for some roles.
set citus.enable_create_role_propagation to off;
grant non_dist_role1 to dist_role1 with admin option;
reset citus.enable_create_role_propagation;
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
grant dist_role2 to non_dist_role1 with admin option;
NOTICE: not propagating GRANT command to other nodes
HINT: Since no grantees are distributed, the GRANT command will not be propagated to other nodes.
grant dist_role3 to "dist_role5'_test" granted by dist_role4;
grant dist_role2 to "dist_role5'_test" granted by dist_role3;
grant dist_role2 to dist_role4 granted by non_dist_role1 ;--will not be propagated since grantor is non-distributed
NOTICE: not propagating GRANT command to other nodes
HINT: Since grantor is not distributed, the GRANT command will not be propagated to other nodes.
grant dist_role4 to "dist_role5'_test" with admin option;
--below command propagates the non_dist_role1 since non_dist_role1 is already granted to dist_role1
--and citus sees granted roles as a dependency and citus propagates the dependent roles
grant dist_role4 to dist_role1 with admin option GRANTED BY "dist_role5'_test";
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
non_dist_role1
(1 row)
grant dist_role4 to dist_role3 with admin option GRANTED BY dist_role1; --fails since already dist_role3 granted to dist_role4
ERROR: role "dist_role4" is a member of role "dist_role3"
grant non_dist_role1 to dist_role4 granted by dist_role1;
ERROR: permission denied to grant privileges as role "dist_role1"
DETAIL: The grantor must have the ADMIN option on role "non_dist_role1".
CONTEXT: while executing command on localhost:xxxxx
grant dist_role3 to dist_role1 with admin option GRANTED BY dist_role4;
grant "dist_role5'_test" to dist_role1 with admin option;
grant "dist_role5'_test" to dist_role3 with admin option GRANTED BY dist_role1;--fails since already dist_role3 granted to "dist_role5'_test"
ERROR: role "dist_role5'_test" is a member of role "dist_role3"
select result FROM run_command_on_all_nodes( select result FROM run_command_on_all_nodes(
$$ $$
SELECT array_to_json(array_agg(row_to_json(t))) SELECT array_to_json(array_agg(row_to_json(t)))
@ -49,15 +70,15 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
); );
result result
--------------------------------------------------------------------- ---------------------------------------------------------------------
[{"member":"\"role5'_test\"","role":"role2","grantor":"role3","admin_option":false},{"member":"\"role5'_test\"","role":"role3","grantor":"role4","admin_option":false},{"member":"\"role5'_test\"","role":"role4","grantor":"postgres","admin_option":true},{"member":"role1","role":"\"role5'_test\"","grantor":"postgres","admin_option":true},{"member":"role1","role":"role2","grantor":"postgres","admin_option":true},{"member":"role1","role":"role3","grantor":"role4","admin_option":true},{"member":"role1","role":"role4","grantor":"\"role5'_test\"","admin_option":true},{"member":"role3","role":"role2","grantor":"role1","admin_option":true},{"member":"role4","role":"role3","grantor":"postgres","admin_option":true}] [{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role1","role":"non_dist_role1","grantor":"postgres","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role2","grantor":"non_dist_role1","admin_option":false},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"\"role5'_test\"","role":"role2","grantor":"role3","admin_option":false},{"member":"\"role5'_test\"","role":"role3","grantor":"role4","admin_option":false},{"member":"\"role5'_test\"","role":"role4","grantor":"postgres","admin_option":true},{"member":"role1","role":"\"role5'_test\"","grantor":"postgres","admin_option":true},{"member":"role1","role":"role2","grantor":"postgres","admin_option":true},{"member":"role1","role":"role3","grantor":"role4","admin_option":true},{"member":"role1","role":"role4","grantor":"\"role5'_test\"","admin_option":true},{"member":"role3","role":"role2","grantor":"role1","admin_option":true},{"member":"role4","role":"role3","grantor":"postgres","admin_option":true}] [{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
(2 rows) (2 rows)
select 1 from citus_add_node ('localhost',:worker_2_port); select 1 from citus_add_node ('localhost',:worker_2_port);
@ -73,20 +94,27 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
); );
result result
--------------------------------------------------------------------- ---------------------------------------------------------------------
[{"member":"\"role5'_test\"","role":"role2","grantor":"role3","admin_option":false},{"member":"\"role5'_test\"","role":"role3","grantor":"role4","admin_option":false},{"member":"\"role5'_test\"","role":"role4","grantor":"postgres","admin_option":true},{"member":"role1","role":"\"role5'_test\"","grantor":"postgres","admin_option":true},{"member":"role1","role":"role2","grantor":"postgres","admin_option":true},{"member":"role1","role":"role3","grantor":"role4","admin_option":true},{"member":"role1","role":"role4","grantor":"\"role5'_test\"","admin_option":true},{"member":"role3","role":"role2","grantor":"role1","admin_option":true},{"member":"role4","role":"role3","grantor":"postgres","admin_option":true}] [{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role1","role":"non_dist_role1","grantor":"postgres","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role2","grantor":"non_dist_role1","admin_option":false},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"\"role5'_test\"","role":"role2","grantor":"role3","admin_option":false},{"member":"\"role5'_test\"","role":"role3","grantor":"role4","admin_option":false},{"member":"\"role5'_test\"","role":"role4","grantor":"postgres","admin_option":true},{"member":"role1","role":"\"role5'_test\"","grantor":"postgres","admin_option":true},{"member":"role1","role":"role2","grantor":"postgres","admin_option":true},{"member":"role1","role":"role3","grantor":"role4","admin_option":true},{"member":"role1","role":"role4","grantor":"\"role5'_test\"","admin_option":true},{"member":"role3","role":"role2","grantor":"role1","admin_option":true},{"member":"role4","role":"role3","grantor":"postgres","admin_option":true}] [{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"\"role5'_test\"","role":"role2","grantor":"role3","admin_option":false},{"member":"\"role5'_test\"","role":"role3","grantor":"role4","admin_option":false},{"member":"\"role5'_test\"","role":"role4","grantor":"postgres","admin_option":true},{"member":"role1","role":"\"role5'_test\"","grantor":"postgres","admin_option":true},{"member":"role1","role":"role2","grantor":"postgres","admin_option":true},{"member":"role1","role":"role3","grantor":"role4","admin_option":true},{"member":"role1","role":"role4","grantor":"\"role5'_test\"","admin_option":true},{"member":"role3","role":"role2","grantor":"role1","admin_option":true},{"member":"role4","role":"role3","grantor":"postgres","admin_option":true}] [{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role1","role":"non_dist_role1","grantor":"postgres","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role2","grantor":"non_dist_role1","admin_option":false},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
(3 rows) (3 rows)
--clean all resources --clean all resources
drop role role1,role2,role3,role4,"role5'_test"; drop role dist_role1,dist_role2,dist_role3,dist_role4,"dist_role5'_test";
drop role non_dist_role1;
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
reset citus.enable_create_role_propagation;
select result FROM run_command_on_all_nodes( select result FROM run_command_on_all_nodes(
$$ $$
SELECT array_to_json(array_agg(row_to_json(t))) SELECT array_to_json(array_agg(row_to_json(t)))
@ -94,7 +122,7 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
@ -106,3 +134,171 @@ select result FROM run_command_on_all_nodes(
(3 rows) (3 rows)
--- Test 2: Tests from non-main database
set citus.enable_create_database_propagation to on;
create database test_granted_by_support;
select 1 from citus_remove_node ('localhost',:worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
\c test_granted_by_support
--here in below block since 'citus.enable_create_role_propagation to off ' is not effective,
--non_dist_role1 is being propagated to dist_role1 unlike main db scenario
--non_dist_role1 will be used for the test scenarios in this section
set citus.enable_create_role_propagation to off;
create role non_dist_role1;
reset citus.enable_create_role_propagation;
--dropping since it isn't non-distributed as intended
drop role non_dist_role1;
--creating non_dist_role1 again in main database
--This is actually non-distributed role
\c regression
set citus.enable_create_role_propagation to off;
create role non_dist_role1;
NOTICE: not propagating CREATE ROLE/USER commands to other nodes
HINT: Connect to other nodes directly to manually create all necessary users and roles.
reset citus.enable_create_role_propagation;
\c test_granted_by_support
create role dist_role1;
create role dist_role1;
ERROR: role "dist_role1" already exists
create role dist_role2;
create role dist_role3;
create role dist_role4;
create role "dist_role5'_test";
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
\c test_granted_by_support
grant dist_role2 to dist_role1 with admin option;
grant dist_role2 to dist_role3 with admin option granted by dist_role1;
grant dist_role3 to dist_role4 with admin option;
-- With enable_create_role_propagation on, all grantees are propagated.
-- To test non-distributed grantor, set this option off for some roles.
\c regression
set citus.enable_create_role_propagation to off;
grant non_dist_role1 to dist_role1 with admin option;
reset citus.enable_create_role_propagation;
\c test_granted_by_support
grant dist_role2 to non_dist_role1 with admin option;
ERROR: failure on connection marked as essential: localhost:xxxxx
CONTEXT: while executing command on localhost:xxxxx
\c test_granted_by_support - - :worker_1_port
grant dist_role3 to "dist_role5'_test" granted by dist_role4;
grant dist_role2 to "dist_role5'_test" granted by dist_role3;
grant dist_role2 to dist_role4 granted by non_dist_role1 ;--will not be propagated since grantor is non-distributed
ERROR: role "non_dist_role1" does not exist
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
\c test_granted_by_support - - :worker_1_port
grant dist_role4 to "dist_role5'_test" with admin option;
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
\c test_granted_by_support
-- Unlike maindb scenario, non-maindb scenario doesn't propagate 'create non_dist_role1' to
--workers as it doesn't create dependency objects for non-distributed roles.
grant dist_role4 to dist_role1 with admin option GRANTED BY "dist_role5'_test";
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
rolname
---------------------------------------------------------------------
(0 rows)
\c test_granted_by_support - - :worker_1_port
grant dist_role4 to dist_role3 with admin option GRANTED BY dist_role1; --fails since already dist_role3 granted to dist_role4
ERROR: role "dist_role4" is a member of role "dist_role3"
grant non_dist_role1 to dist_role4 granted by dist_role1;
ERROR: role "non_dist_role1" does not exist
grant dist_role3 to dist_role1 with admin option GRANTED BY dist_role4;
grant "dist_role5'_test" to dist_role1 with admin option;
grant "dist_role5'_test" to dist_role3 with admin option GRANTED BY dist_role1;--fails since already dist_role3 granted to "dist_role5'_test"
ERROR: role "dist_role5'_test" is a member of role "dist_role3"
\c regression - - :master_port
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
result
---------------------------------------------------------------------
[{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role1","role":"non_dist_role1","grantor":"postgres","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
(2 rows)
select 1 from citus_add_node ('localhost',:worker_2_port);
?column?
---------------------------------------------------------------------
1
(1 row)
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
result
---------------------------------------------------------------------
[{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role1","role":"non_dist_role1","grantor":"postgres","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
[{"member":"dist_role1","role":"\"dist_role5'_test\"","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role2","grantor":"postgres","admin_option":true},{"member":"dist_role1","role":"dist_role3","grantor":"dist_role4","admin_option":true},{"member":"dist_role1","role":"dist_role4","grantor":"\"dist_role5'_test\"","admin_option":true},{"member":"dist_role3","role":"dist_role2","grantor":"dist_role1","admin_option":true},{"member":"dist_role4","role":"dist_role3","grantor":"postgres","admin_option":true}]
(3 rows)
--clean all resources
set citus.enable_create_database_propagation to on;
drop database test_granted_by_support;
drop role dist_role1,dist_role2,dist_role3,dist_role4,"dist_role5'_test";
drop role non_dist_role1;
drop role if exists non_dist_role1;
NOTICE: role "non_dist_role1" does not exist, skipping
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
result
---------------------------------------------------------------------
(3 rows)
reset citus.enable_create_database_propagation;

View File

@ -1,31 +1,56 @@
-- Active: 1700033167033@@localhost@9700@gurkanindibay@public -- Active: 1700033167033@@localhost@9700@gurkanindibay@public
--In below tests, complex role hierarchy is created and then granted by support is tested. --In below tests, complex role hierarchy is created and then granted by support is tested.
--- Test 1: Tests from main database
select 1 from citus_remove_node ('localhost',:worker_2_port); select 1 from citus_remove_node ('localhost',:worker_2_port);
set citus.enable_create_role_propagation to off;
create role non_dist_role1;
reset citus.enable_create_role_propagation;
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
create role role1; create role dist_role1;
create role role2; create role dist_role2;
create role role3; create role dist_role3;
create role role4; create role dist_role4;
create role "role5'_test"; create role "dist_role5'_test";
grant role2 to role1 with admin option; grant dist_role2 to dist_role1 with admin option;
grant role2 to role3 with admin option granted by role1; grant dist_role2 to dist_role3 with admin option granted by dist_role1;
grant role3 to role4 with admin option; grant dist_role3 to dist_role4 with admin option;
grant role3 to "role5'_test" granted by role4;
grant role2 to "role5'_test" granted by role3;
grant role4 to "role5'_test" with admin option;
grant role4 to role1 with admin option GRANTED BY "role5'_test";
grant role4 to role3 with admin option GRANTED BY role1;
grant role3 to role1 with admin option GRANTED BY role4;
grant "role5'_test" to role1 with admin option;
grant "role5'_test" to role3 with admin option GRANTED BY role1;
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option -- With enable_create_role_propagation on, all grantees are propagated.
FROM pg_auth_members -- To test non-distributed grantor, set this option off for some roles.
WHERE member::regrole::text in set citus.enable_create_role_propagation to off;
('role1','role2','role3','role4','"role5''_test"') grant non_dist_role1 to dist_role1 with admin option;
order by member::regrole::text, roleid::regrole::text; reset citus.enable_create_role_propagation;
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
grant dist_role2 to non_dist_role1 with admin option;
grant dist_role3 to "dist_role5'_test" granted by dist_role4;
grant dist_role2 to "dist_role5'_test" granted by dist_role3;
grant dist_role2 to dist_role4 granted by non_dist_role1 ;--will not be propagated since grantor is non-distributed
grant dist_role4 to "dist_role5'_test" with admin option;
--below command propagates the non_dist_role1 since non_dist_role1 is already granted to dist_role1
--and citus sees granted roles as a dependency and citus propagates the dependent roles
grant dist_role4 to dist_role1 with admin option GRANTED BY "dist_role5'_test";
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
grant dist_role4 to dist_role3 with admin option GRANTED BY dist_role1; --fails since already dist_role3 granted to dist_role4
grant non_dist_role1 to dist_role4 granted by dist_role1;
grant dist_role3 to dist_role1 with admin option GRANTED BY dist_role4;
grant "dist_role5'_test" to dist_role1 with admin option;
grant "dist_role5'_test" to dist_role3 with admin option GRANTED BY dist_role1;--fails since already dist_role3 granted to "dist_role5'_test"
select result FROM run_command_on_all_nodes( select result FROM run_command_on_all_nodes(
@ -35,7 +60,139 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
select 1 from citus_add_node ('localhost',:worker_2_port);
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
--clean all resources
drop role dist_role1,dist_role2,dist_role3,dist_role4,"dist_role5'_test";
drop role non_dist_role1;
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
reset citus.enable_create_role_propagation;
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text
) t
$$
);
--- Test 2: Tests from non-main database
set citus.enable_create_database_propagation to on;
create database test_granted_by_support;
select 1 from citus_remove_node ('localhost',:worker_2_port);
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
\c test_granted_by_support
--here in below block since 'citus.enable_create_role_propagation to off ' is not effective,
--non_dist_role1 is being propagated to dist_role1 unlike main db scenario
--non_dist_role1 will be used for the test scenarios in this section
set citus.enable_create_role_propagation to off;
create role non_dist_role1;
reset citus.enable_create_role_propagation;
--dropping since it isn't non-distributed as intended
drop role non_dist_role1;
--creating non_dist_role1 again in main database
--This is actually non-distributed role
\c regression
set citus.enable_create_role_propagation to off;
create role non_dist_role1;
reset citus.enable_create_role_propagation;
\c test_granted_by_support
create role dist_role1;
create role dist_role1;
create role dist_role2;
create role dist_role3;
create role dist_role4;
create role "dist_role5'_test";
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
\c test_granted_by_support
grant dist_role2 to dist_role1 with admin option;
grant dist_role2 to dist_role3 with admin option granted by dist_role1;
grant dist_role3 to dist_role4 with admin option;
-- With enable_create_role_propagation on, all grantees are propagated.
-- To test non-distributed grantor, set this option off for some roles.
\c regression
set citus.enable_create_role_propagation to off;
grant non_dist_role1 to dist_role1 with admin option;
reset citus.enable_create_role_propagation;
\c test_granted_by_support
grant dist_role2 to non_dist_role1 with admin option;
\c test_granted_by_support - - :worker_1_port
grant dist_role3 to "dist_role5'_test" granted by dist_role4;
grant dist_role2 to "dist_role5'_test" granted by dist_role3;
grant dist_role2 to dist_role4 granted by non_dist_role1 ;--will not be propagated since grantor is non-distributed
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
\c test_granted_by_support - - :worker_1_port
grant dist_role4 to "dist_role5'_test" with admin option;
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
\c test_granted_by_support
-- Unlike maindb scenario, non-maindb scenario doesn't propagate 'create non_dist_role1' to
--workers as it doesn't create dependency objects for non-distributed roles.
grant dist_role4 to dist_role1 with admin option GRANTED BY "dist_role5'_test";
\c regression - - :master_port
select r.rolname from pg_roles r inner join pg_dist_object o on r.oid= objid where r.rolname = 'non_dist_role1';
\c test_granted_by_support - - :worker_1_port
grant dist_role4 to dist_role3 with admin option GRANTED BY dist_role1; --fails since already dist_role3 granted to dist_role4
grant non_dist_role1 to dist_role4 granted by dist_role1;
grant dist_role3 to dist_role1 with admin option GRANTED BY dist_role4;
grant "dist_role5'_test" to dist_role1 with admin option;
grant "dist_role5'_test" to dist_role3 with admin option GRANTED BY dist_role1;--fails since already dist_role3 granted to "dist_role5'_test"
\c regression - - :master_port
select result FROM run_command_on_all_nodes(
$$
SELECT array_to_json(array_agg(row_to_json(t)))
FROM (
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members
WHERE member::regrole::text in
('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
@ -49,14 +206,23 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
); );
--clean all resources --clean all resources
drop role role1,role2,role3,role4,"role5'_test";
set citus.enable_create_database_propagation to on;
drop database test_granted_by_support;
drop role dist_role1,dist_role2,dist_role3,dist_role4,"dist_role5'_test";
drop role non_dist_role1;
drop role if exists non_dist_role1;
select result FROM run_command_on_all_nodes( select result FROM run_command_on_all_nodes(
$$ $$
@ -65,8 +231,9 @@ select result FROM run_command_on_all_nodes(
SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option SELECT member::regrole, roleid::regrole as role, grantor::regrole, admin_option
FROM pg_auth_members FROM pg_auth_members
WHERE member::regrole::text in WHERE member::regrole::text in
('role1','role2','role3','role4','"role5''_test"') ('dist_role1','dist_role2','dist_role3','dist_role4','"role5''_test"')
order by member::regrole::text, roleid::regrole::text order by member::regrole::text, roleid::regrole::text
) t ) t
$$ $$
); );
reset citus.enable_create_database_propagation;