Skip to content

Commit

Permalink
Support Securityadmin fixed server role (babelfish-for-postgresql#67)
Browse files Browse the repository at this point in the history
Added support for new fixed server role securityadmin. This role has following privileges with it:

Members of the securityadmin fixed server role can manage logins and their properties.
They can GRANT, DENY, and REVOKE server-level permissions.
securityadmin can also GRANT, DENY, and REVOKE database-level permissions if they have access to a database.

Original PR with all the comments babelfish-for-postgresql#2907

Issue resolved: BABEL-5040
Signed-off-by: ANJU BHARTI <[email protected]>
  • Loading branch information
anju15bharti authored and tanscorpio7 committed Oct 31, 2024
1 parent 5444c49 commit ac10c60
Show file tree
Hide file tree
Showing 41 changed files with 3,332 additions and 142 deletions.
13 changes: 9 additions & 4 deletions contrib/babelfishpg_tds/src/backend/tds/tdsutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,14 +939,17 @@ is_babelfish_role(const char *role)
Oid bbf_master_guest_oid;
Oid bbf_tempdb_guest_oid;
Oid bbf_msdb_guest_oid;
Oid securityadmin_oid;

sysadmin_oid = get_role_oid(BABELFISH_SYSADMIN, true); /* missing OK */
role_oid = get_role_oid(role, true); /* missing OK */
securityadmin_oid = get_role_oid(BABELFISH_SECURITYADMIN, true); /* missing OK */

if (!OidIsValid(sysadmin_oid) || !OidIsValid(role_oid))
return false;

if (is_member_of_role(sysadmin_oid, role_oid) ||
is_member_of_role(securityadmin_oid, role_oid) ||
pg_strcasecmp(role, BABELFISH_ROLE_ADMIN) == 0) /* check if it is bbf_role_admin */
return true;

Expand Down Expand Up @@ -1204,11 +1207,13 @@ handle_grant_role(GrantRoleStmt *grant_stmt)
{
ListCell *item;
Oid bbf_role_admin_oid = InvalidOid;
Oid securityadmin_oid = InvalidOid;

if (MyProcPort->is_tds_conn && sql_dialect == SQL_DIALECT_TSQL)
return true;

bbf_role_admin_oid = get_role_oid(BABELFISH_ROLE_ADMIN, false);
securityadmin_oid = get_role_oid(BABELFISH_SECURITYADMIN, false);

/*
* Allow GRANT ROLE if current user is bbf_role_admin as we need
Expand All @@ -1218,7 +1223,7 @@ handle_grant_role(GrantRoleStmt *grant_stmt)
if (bbf_role_admin_oid == GetUserId())
return true;

/* Restrict roles to added as a member of bbf_role_admin */
/* Restrict roles to added as a member of bbf_role_admin/securityadmin */
foreach(item, grant_stmt->granted_roles)
{
AccessPriv *priv = (AccessPriv *) lfirst(item);
Expand All @@ -1229,18 +1234,18 @@ handle_grant_role(GrantRoleStmt *grant_stmt)
continue;

roleid = get_role_oid(rolename, false);
if (OidIsValid(roleid) && roleid == bbf_role_admin_oid)
if (OidIsValid(roleid) && (roleid == bbf_role_admin_oid || roleid == securityadmin_oid))
check_babelfish_alterrole_restictions(false);
}

/* Restrict grant to/from bbf_role_admin role */
/* Restrict grant to/from bbf_role_admin/securityadmin role */
foreach(item, grant_stmt->grantee_roles)
{
RoleSpec *rolespec = lfirst_node(RoleSpec, item);
Oid roleid;

roleid = get_rolespec_oid(rolespec, false);
if (OidIsValid(roleid) && roleid == bbf_role_admin_oid)
if (OidIsValid(roleid) && (roleid == bbf_role_admin_oid || roleid == securityadmin_oid))
check_babelfish_alterrole_restictions(false);
}

Expand Down
1 change: 1 addition & 0 deletions contrib/babelfishpg_tds/src/include/tds_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ extern ProcessUtility_hook_type next_ProcessUtility;
#define PUBLIC_ROLE_NAME "public"
#define BABELFISH_SYSADMIN "sysadmin"
#define BABELFISH_ROLE_ADMIN "bbf_role_admin"
#define BABELFISH_SECURITYADMIN "securityadmin"

/* Functions in backend/tds/tdscomm.c */
extern void TdsSetMessageType(uint8_t msgType);
Expand Down
13 changes: 8 additions & 5 deletions contrib/babelfishpg_tsql/sql/babelfishpg_tsql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2060,8 +2060,8 @@ BEGIN
ELSIF role = 'public' COLLATE sys.database_default THEN
RETURN 1;

ELSIF role = 'sysadmin' COLLATE sys.database_default THEN
has_role = pg_has_role(login::TEXT, role::TEXT, 'MEMBER');
ELSIF role = 'sysadmin' COLLATE sys.database_default OR role = 'securityadmin' COLLATE sys.database_default THEN
has_role = (pg_has_role(login::TEXT, role::TEXT, 'MEMBER') OR pg_has_role(login::TEXT, 'sysadmin'::TEXT, 'MEMBER'));
IF has_role THEN
RETURN 1;
ELSE
Expand All @@ -2070,9 +2070,7 @@ BEGIN

ELSIF role COLLATE sys.database_default IN (
'serveradmin',
'securityadmin',
'setupadmin',
'securityadmin',
'processadmin',
'dbcreator',
'diskadmin',
Expand Down Expand Up @@ -2427,7 +2425,12 @@ CAST(
ELSE 0
END
AS INT) AS sysadmin,
CAST(0 AS INT) AS securityadmin,
CAST(
CASE
WHEN is_srvrolemember('securityadmin', Base.name) = 1 THEN 1
ELSE 0
END
AS INT) AS securityadmin,
CAST(0 AS INT) AS serveradmin,
CAST(0 AS INT) AS setupadmin,
CAST(0 AS INT) AS processadmin,
Expand Down
14 changes: 10 additions & 4 deletions contrib/babelfishpg_tsql/sql/ownership.sql
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ CREATE OR REPLACE PROCEDURE initialize_babelfish ( sa_name VARCHAR(128) )
LANGUAGE plpgsql
AS $$
DECLARE
reserved_roles varchar[] := ARRAY['sysadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner', 'msdb_dbo', 'msdb_guest', 'msdb_db_owner'];
reserved_roles varchar[] := ARRAY['sysadmin', 'securityadmin', 'master_dbo', 'master_guest', 'master_db_owner', 'tempdb_dbo', 'tempdb_guest', 'tempdb_db_owner', 'msdb_dbo', 'msdb_guest', 'msdb_db_owner'];
user_id oid := -1;
db_name name := NULL;
role_name varchar;
Expand All @@ -285,11 +285,13 @@ BEGIN
RAISE E'Could not initialize babelfish with given role name: % is not the DB owner of current database.', sa_name;
END IF;

EXECUTE format('CREATE ROLE securityadmin CREATEROLE INHERIT PASSWORD NULL');
EXECUTE format('CREATE ROLE bbf_role_admin CREATEDB CREATEROLE INHERIT PASSWORD NULL');
EXECUTE format('GRANT CREATE ON DATABASE %s TO bbf_role_admin WITH GRANT OPTION', CURRENT_DATABASE());
EXECUTE format('GRANT %I to bbf_role_admin WITH ADMIN TRUE;', sa_name);
EXECUTE format('CREATE ROLE sysadmin CREATEDB CREATEROLE INHERIT ROLE %I', sa_name);
EXECUTE format('GRANT sysadmin TO bbf_role_admin WITH ADMIN TRUE');
EXECUTE format('GRANT securityadmin TO bbf_role_admin WITH ADMIN TRUE');
EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_partition_function_seq TO sysadmin WITH GRANT OPTION');
EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_partition_scheme_seq TO sysadmin WITH GRANT OPTION');
EXECUTE format('GRANT USAGE, SELECT ON SEQUENCE sys.babelfish_db_seq TO sysadmin WITH GRANT OPTION');
Expand All @@ -299,6 +301,7 @@ BEGIN
CALL sys.babel_initialize_logins(sa_name);
CALL sys.babel_initialize_logins('sysadmin');
CALL sys.babel_initialize_logins('bbf_role_admin');
CALL sys.babel_initialize_logins('securityadmin');
CALL sys.babel_create_builtin_dbs(sa_name);
CALL sys.initialize_babel_extras();
-- run analyze for all babelfish catalog
Expand All @@ -320,6 +323,8 @@ BEGIN
DROP ROLE sysadmin;
DROP OWNED BY bbf_role_admin;
DROP ROLE bbf_role_admin;
DROP OWNED BY securityadmin;
DROP ROLE securityadmin;
END
$$;

Expand Down Expand Up @@ -365,7 +370,8 @@ CAST(CASE WHEN Ext.type = 'R' THEN NULL ELSE Ext.credential_id END AS INT) AS cr
CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.owning_principal_id END AS INT) AS owning_principal_id,
CAST(CASE WHEN Ext.type = 'R' THEN 1 ELSE Ext.is_fixed_role END AS sys.BIT) AS is_fixed_role
FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname
WHERE (pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER')
WHERE (pg_has_role(suser_id(), 'sysadmin'::TEXT, 'MEMBER')
OR pg_has_role(suser_id(), 'securityadmin'::TEXT, 'MEMBER')
OR Ext.orig_loginname = suser_name()
OR Ext.orig_loginname = (SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = CURRENT_DATABASE()) COLLATE sys.database_default
OR Ext.type = 'R')
Expand Down Expand Up @@ -501,8 +507,8 @@ CAST(Ext.orig_loginname AS sys.nvarchar(128)) AS name,
CAST('SERVER ROLE' AS sys.nvarchar(128)) AS type,
CAST ('GRANT OR DENY' as sys.nvarchar(128)) as usage
FROM pg_catalog.pg_roles AS Base INNER JOIN sys.babelfish_authid_login_ext AS Ext ON Base.rolname = Ext.rolname
WHERE Ext.type = 'R' AND
(pg_has_role(sys.suser_id(), 'sysadmin'::TEXT, 'MEMBER'));
WHERE Ext.type = 'R'
AND bbf_is_member_of_role_nosuper(sys.suser_id(), Base.oid);

GRANT SELECT ON sys.login_token TO PUBLIC;

Expand Down
4 changes: 4 additions & 0 deletions contrib/babelfishpg_tsql/sql/sys_functions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4530,6 +4530,10 @@ $$
$$
LANGUAGE SQL STRICT STABLE PARALLEL SAFE;

CREATE OR REPLACE FUNCTION sys.bbf_is_member_of_role_nosuper(OID, OID)
RETURNS BOOLEAN AS 'babelfishpg_tsql', 'bbf_is_member_of_role_nosuper'
LANGUAGE C STABLE STRICT PARALLEL SAFE;

CREATE OR REPLACE FUNCTION sys.replace (input_string sys.VARCHAR, pattern sys.VARCHAR, replacement sys.VARCHAR)
RETURNS sys.VARCHAR AS
$BODY$
Expand Down
Loading

0 comments on commit ac10c60

Please sign in to comment.