diff --git a/docs/en_US/images/role_membership.png b/docs/en_US/images/role_membership.png index 55ec9fd1264..1da4b505e62 100644 Binary files a/docs/en_US/images/role_membership.png and b/docs/en_US/images/role_membership.png differ diff --git a/docs/en_US/images/role_sql.png b/docs/en_US/images/role_sql.png index 5ba387fbbbf..fa4a3d5450c 100644 Binary files a/docs/en_US/images/role_sql.png and b/docs/en_US/images/role_sql.png differ diff --git a/docs/en_US/role_dialog.rst b/docs/en_US/role_dialog.rst index 1f2387aa04c..3745f5f2f3d 100644 --- a/docs/en_US/role_dialog.rst +++ b/docs/en_US/role_dialog.rst @@ -65,15 +65,26 @@ Use the *Privileges* tab to grant privileges to the role. * Move the *Bypass RLS?* switch to the *Yes* position to control whether a role can bypasses every row-level security (RLS) policy. The default value is *No*. +Click the *Membership* tab to continue. + .. image:: images/role_membership.png :alt: Role dialog membership tab :align: center -* Specify member of the role in the *Member of* field and specify the members in the *Member* field. - Confirm each selection by checking the checkbox to the right of the role name; - delete a selection by clicking the *x* to the left of the role name. - Membership conveys the privileges granted to the specified role to each of - its members. +Use the *Membership* tab to define role memberships. A role can be a member of +other roles and can have other roles as members. + +* Use *Member of* section to specify roles of which the current role + is a member. To assign *Admin Option* for a selected role, click on + the appropriate checkbox. +* Use *Members* section to specify roles that are members of the current + role. To assign *Admin Option* for a selected role, click on the appropriate checkbox. + +Click the *Add* icon (+) to add more roles; to discard a +role, click the trash icon to the left of the row and confirm the deletion +in the *Delete Row* popup. + +**Note:** Apart from *Admin Option*, *Inherit Option* and *Set Option* are available for both *Member of* section and *Members* section from PostgreSQL version >= 16. Click the *Parameters* tab to continue. diff --git a/web/pgadmin/browser/server_groups/servers/roles/__init__.py b/web/pgadmin/browser/server_groups/servers/roles/__init__.py index 45e2cc5f34e..15ecd9cc15c 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/__init__.py +++ b/web/pgadmin/browser/server_groups/servers/roles/__init__.py @@ -207,40 +207,32 @@ def _process_rolemembership(self, id, data): :param id: id of role :param data: input role data """ - def _part_dict_list(dict_list, condition, list_key=None): + def _part_dict_list(dict_list, condition): ret_val = [] for d in dict_list: if condition(d): - ret_val.append(d[list_key]) + ret_val.append(d) return ret_val if id == -1: - data['members'] = [] - data['admins'] = [] - - data['admins'] = _part_dict_list( - data['rolmembership'], lambda d: d['admin'], 'role') - data['members'] = _part_dict_list( - data['rolmembership'], lambda d: not d['admin'], 'role') + data['rolmembership_list'] = data['rolmembership'] else: - data['admins'] = _part_dict_list( - data['rolmembership'].get('added', []), - lambda d: d['admin'], 'role') - data['members'] = _part_dict_list( - data['rolmembership'].get('added', []), - lambda d: not d['admin'], 'role') - - data['admins'].extend(_part_dict_list( - data['rolmembership'].get('changed', []), - lambda d: d['admin'], 'role')) - data['revoked_admins'] = _part_dict_list( - data['rolmembership'].get('changed', []), - lambda d: not d['admin'], 'role') - - data['revoked'] = _part_dict_list( - data['rolmembership'].get('deleted', []), - lambda _: True, 'role') + data['rolmembership_list'] = data['rolmembership'].get('added', []) + + if self.manager.version < 160000: + data['rolmembership_list'].extend(_part_dict_list( + data['rolmembership'].get('changed', []), + lambda d: d['admin'])) + data['rolmembership_revoked_admins'] = _part_dict_list( + data['rolmembership'].get('changed', []), + lambda d: not d['admin']) + else: + data['rolmembership_list'].extend( + data['rolmembership'].get('changed', [])) + + data['rolmembership_revoked_list'] = ( + data['rolmembership'].get('deleted', [])) def _process_rolmembers(self, id, data): """ @@ -248,39 +240,32 @@ def _process_rolmembers(self, id, data): :param id: :param data: """ - def _part_dict_list(dict_list, condition, list_key=None): + def _part_dict_list(dict_list, condition): ret_val = [] for d in dict_list: if condition(d): - ret_val.append(d[list_key]) + ret_val.append(d) return ret_val if id == -1: - data['rol_members'] = [] - data['rol_admins'] = [] + data['rol_members_list'] = data['rolmembers'] - data['rol_admins'] = _part_dict_list( - data['rolmembers'], lambda d: d['admin'], 'role') - data['rol_members'] = _part_dict_list( - data['rolmembers'], lambda d: not d['admin'], 'role') else: - data['rol_admins'] = _part_dict_list( - data['rolmembers'].get('added', []), - lambda d: d['admin'], 'role') - data['rol_members'] = _part_dict_list( - data['rolmembers'].get('added', []), - lambda d: not d['admin'], 'role') - - data['rol_admins'].extend(_part_dict_list( - data['rolmembers'].get('changed', []), - lambda d: d['admin'], 'role')) - data['rol_revoked_admins'] = _part_dict_list( - data['rolmembers'].get('changed', []), - lambda d: not d['admin'], 'role') - - data['rol_revoked'] = _part_dict_list( - data['rolmembers'].get('deleted', []), - lambda _: True, 'role') + data['rol_members_list'] = data['rolmembers'].get('added', []) + + if self.manager.version < 160000: + data['rol_members_list'].extend(_part_dict_list( + data['rolmembers'].get('changed', []), + lambda d: d['admin'])) + data['rol_members_revoked_admins'] = _part_dict_list( + data['rolmembers'].get('changed', []), + lambda d: not d['admin']) + else: + data['rol_members_list'].extend( + data['rolmembers'].get('changed', [])) + + data['rol_members_revoked_list'] = ( + data['rolmembers'].get('deleted', [])) def _validate_rolemembers(self, id, data): """ @@ -298,13 +283,21 @@ def _validate_rolemembers(self, id, data): rolmembers:[{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ]""") - if not self._validate_input_dict_for_new(data['rolmembers'], - ['role', 'admin']): + if (self.manager.version < 160000 and + not self._validate_input_dict_for_new( + data['rolmembers'], ['role', 'admin'])): + return msg + elif (self.manager.version >= 160000 and + not self._validate_input_dict_for_new( + data['rolmembers'], + ['role', 'admin', 'inherit', 'set'])): return msg self._process_rolmembers(id, data) @@ -316,26 +309,38 @@ def _validate_rolemembers(self, id, data): rolmembers:{ 'added': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ], 'deleted': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ], 'updated': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ] """) - if not self._validate_input_dict_for_update(data['rolmembers'], - ['role', 'admin'], - ['role']): + if (self.manager.version < 160000 and + not self._validate_input_dict_for_update( + data['rolmembers'], ['role', 'admin'], ['role'])): + return msg + elif (self.manager.version >= 160000 and + not self._validate_input_dict_for_update( + data['rolmembers'], + ['role', 'admin', 'inherit', 'set'], + ['role'])): return msg self._process_rolmembers(id, data) @@ -357,13 +362,21 @@ def _validate_rolemembership(self, id, data): rolmembership:[{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ]""") - if not self._validate_input_dict_for_new( - data['rolmembership'], ['role', 'admin']): + if (self.manager.version < 160000 and + not self._validate_input_dict_for_new( + data['rolmembership'], ['role', 'admin'])): + return msg + elif (self.manager.version >= 160000 and + not self._validate_input_dict_for_new( + data['rolmembership'], + ['role', 'admin', 'inherit', 'set'])): return msg self._process_rolemembership(id, data) @@ -375,25 +388,38 @@ def _validate_rolemembership(self, id, data): rolmembership:{ 'added': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ], 'deleted': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ], 'updated': [{ role: [rolename], - admin: True/False + admin: True/False, + inherit: True/False, + set: True/False, }, ... ] """) - if not self._validate_input_dict_for_update( - data['rolmembership'], ['role', 'admin'], ['role']): + if (self.manager.version < 160000 and + not self._validate_input_dict_for_update( + data['rolmembership'], ['role', 'admin'], ['role'])): + return msg + elif (self.manager.version >= 160000 and + not self._validate_input_dict_for_update( + data['rolmembership'], + ['role', 'admin', 'inherit', 'set'], + ['role'])): return msg self._process_rolemembership(id, data) @@ -792,16 +818,25 @@ def _set_seclabels(self, row): }) row['seclabels'] = res - def _set_rolemembership(self, row): + def _set_rolemembers(self, row): if 'rolmembers' in row and row['rolmembers'] is not None: rolmembers = [] for role in row['rolmembers']: - role = re.search(r'([01])(.+)', role) - rolmembers.append({ - 'role': role.group(2), - 'admin': True if role.group(1) == '1' else False - }) + if self.manager.version < 160000: + role = re.search(r'([01])(.+)', role) + rolmembers.append({ + 'role': role.group(2), + 'admin': True if role.group(1) == '1' else False + }) + else: + role = re.search(r'([01])([01])([01])(.+)', role) + rolmembers.append({ + 'role': role.group(4), + 'admin': True if role.group(1) == '1' else False, + 'inherit': True if role.group(2) == '1' else False, + 'set': True if role.group(3) == '1' else False + }) row['rolmembers'] = rolmembers def transform(self, rset): @@ -810,14 +845,23 @@ def transform(self, rset): roles = row['rolmembership'] row['rolpassword'] = '' for role in roles: - role = re.search(r'([01])(.+)', role) - res.append({ - 'role': role.group(2), - 'admin': True if role.group(1) == '1' else False - }) + if self.manager.version < 160000: + role = re.search(r'([01])(.+)', role) + res.append({ + 'role': role.group(2), + 'admin': True if role.group(1) == '1' else False + }) + else: + role = re.search(r'([01])([01])([01])(.+)', role) + res.append({ + 'role': role.group(4), + 'admin': True if role.group(1) == '1' else False, + 'inherit': True if role.group(2) == '1' else False, + 'set': True if role.group(3) == '1' else False + }) row['rolmembership'] = res self._set_seclabels(row) - self._set_rolemembership(row) + self._set_rolemembers(row) @check_precondition(action='properties') def properties(self, gid, sid, rid): diff --git a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.ui.js b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.ui.js index 5bf596fcc5a..098b0e52924 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/static/js/role.ui.js +++ b/web/pgadmin/browser/server_groups/servers/roles/static/js/role.ui.js @@ -58,12 +58,12 @@ export default class RoleSchema extends BaseUISchema { memberDataFormatter(rawData) { let members = ''; if(_.isObject(rawData)) { + const serverVersion = this.nodeInfo && this.nodeInfo.server && this.nodeInfo.server.version || 0; rawData.forEach(member => { - let withAdmin = ''; - if(member.admin) { withAdmin = ' [WITH ADMIN]';} + let badges = serverVersion >= 160000 ? ` [WITH ADMIN ${member.admin.toString().toUpperCase()}, INHERIT ${member.inherit.toString().toUpperCase()}, SET ${member.set.toString().toUpperCase()}]` : member.admin ? ' [WITH ADMIN OPTION]' : ''; if (members.length > 0) { members += ', '; } - members = members + (member.role + withAdmin); + members = members + (member.role + badges); }); } return members; @@ -177,7 +177,7 @@ export default class RoleSchema extends BaseUISchema { type: 'text', controlProps: { formatter: { - fromRaw: obj.memberDataFormatter, + fromRaw: (raw) => obj.memberDataFormatter(raw), }, } }, @@ -198,7 +198,7 @@ export default class RoleSchema extends BaseUISchema { type: 'text', controlProps: { formatter: { - fromRaw: obj.memberDataFormatter, + fromRaw: (raw) => obj.memberDataFormatter(raw), }, } }, diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/create.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/create.sql new file mode 100644 index 00000000000..5aa6f2d1e1e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/create.sql @@ -0,0 +1,62 @@ +{% import 'macros/security.macros' as SECLABEL %} +{% import 'macros/variable.macros' as VARIABLE %} +CREATE ROLE {{ conn|qtIdent(data.rolname) }} WITH{% if data.rolcanlogin and data.rolcanlogin is sameas True %} + + LOGIN{% else %} + + NOLOGIN{% endif %}{% if data.rolsuper %} + + SUPERUSER{% else %} + + NOSUPERUSER{% endif %}{% if data.rolcreatedb %} + + CREATEDB{% else %} + + NOCREATEDB{% endif %}{% if data.rolcreaterole %} + + CREATEROLE{% else %} + + NOCREATEROLE{% endif %}{% if data.rolinherit is sameas true %} + + INHERIT{% else %} + + NOINHERIT{% endif %}{% if data.rolreplication %} + + REPLICATION{% else %} + + NOREPLICATION{% endif %}{% if data.rolbypassrls %} + + BYPASSRLS{% else %} + + NOBYPASSRLS{% endif %}{% if 'rolconnlimit' in data and data.rolconnlimit is number and data.rolconnlimit >= -1 %} + + CONNECTION LIMIT {{ data.rolconnlimit }}{% endif %}{% if data.rolvaliduntil and data.rolvaliduntil is not none %} + + VALID UNTIL {{ data.rolvaliduntil|qtLiteral(conn) }} {% endif %}{% if data.rolpassword %} + + PASSWORD {% if data.rolpassword is none %}NULL{% else %}{% if dummy %}'xxxxxx'{% else %} {{ data.rolpassword|qtLiteral(conn) }}{% endif %}{% endif %}{% endif %}; +{% if data.rolmembership_list and data.rolmembership_list|length > 0 %} +{% for item in data.rolmembership_list %} + +GRANT {{ conn|qtIdent(item.role) }} TO {{ conn|qtIdent(data.rolname) }}{% if 'admin' in item or 'inherit' in item or 'set' in item %} WITH ADMIN {{ item.admin }}, INHERIT {{ item.inherit }}, SET {{ item.set }}{% endif %}; +{% endfor %} +{% endif %} +{% if data.seclabels and data.seclabels|length > 0 %} +{% for r in data.seclabels %} + +{{ SECLABEL.APPLY(conn, 'ROLE', data.rolname, r.provider, r.label) }} +{% endfor %}{% endif %}{% if data.variables %} + +{% for var in data.variables %} + +{{ VARIABLE.APPLY(conn, var.database, data.rolname, var.name, var.value) }} +{% endfor %}{% endif %}{% if data.description %} + +COMMENT ON ROLE {{ conn|qtIdent(data.rolname) }} IS {{ data.description|qtLiteral(conn) }}; +{% endif %} +{% if data.rol_members_list and data.rol_members_list|length > 0 %} +{% for item in data.rol_members_list %} + +GRANT {{ conn|qtIdent(data.rolname) }} TO {{ conn|qtIdent(item.role) }}{% if 'admin' in item or 'inherit' in item or 'set' in item %} WITH ADMIN {{ item.admin }}, INHERIT {{ item.inherit }}, SET {{ item.set }}{% endif %}; +{% endfor %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/properties.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/properties.sql new file mode 100644 index 00000000000..e98ebaa5186 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/properties.sql @@ -0,0 +1,37 @@ +SELECT + r.oid, r.*, + pg_catalog.shobj_description(r.oid, 'pg_authid') AS description, + ARRAY( + SELECT + CASE WHEN am.admin_option THEN '1' ELSE '0' END + || CASE WHEN am.inherit_option THEN '1' ELSE '0' END + || CASE WHEN am.set_option THEN '1' ELSE '0' END + || rm.rolname + FROM + (SELECT * FROM pg_catalog.pg_auth_members WHERE member = r.oid) am + LEFT JOIN pg_catalog.pg_roles rm ON (rm.oid = am.roleid) + ORDER BY rm.rolname + ) AS rolmembership, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_shseclabel sl1 WHERE sl1.objoid=r.oid) AS seclabels + {% if rid %} + ,ARRAY( + SELECT + CASE WHEN pg.admin_option THEN '1' ELSE '0' END + || CASE WHEN pg.inherit_option THEN '1' ELSE '0' END + || CASE WHEN pg.set_option THEN '1' ELSE '0' END + || pg.usename + FROM + (SELECT pg_roles.rolname AS usename, + pg_auth_members.admin_option AS admin_option, + pg_auth_members.inherit_option AS inherit_option, + pg_auth_members.set_option AS set_option + FROM pg_roles + JOIN pg_auth_members ON pg_roles.oid=pg_auth_members.member AND pg_auth_members.roleid={{ rid|qtLiteral(conn) }}::oid) pg + ) rolmembers + {% endif %} +FROM + pg_catalog.pg_roles r +{% if rid %} +WHERE r.oid = {{ rid|qtLiteral(conn) }}::oid +{% endif %} +ORDER BY r.rolcanlogin, r.rolname diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/sql.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/sql.sql new file mode 100644 index 00000000000..455b3b1167f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/sql.sql @@ -0,0 +1,130 @@ +SELECT + pg_catalog.array_to_string(array_agg(sql), E'\n\n') AS sql +FROM +(SELECT + '-- Role: ' || + pg_catalog.quote_ident(rolname) || + E'\n-- DROP ROLE IF EXISTS ' || + pg_catalog.quote_ident(rolname) || E';\n\nCREATE ROLE ' || + pg_catalog.quote_ident(rolname) || E' WITH\n ' || + CASE WHEN rolcanlogin THEN 'LOGIN' ELSE 'NOLOGIN' END || E'\n ' || + CASE WHEN rolsuper THEN 'SUPERUSER' ELSE 'NOSUPERUSER' END || E'\n ' || + CASE WHEN rolinherit THEN 'INHERIT' ELSE 'NOINHERIT' END || E'\n ' || + CASE WHEN rolcreatedb THEN 'CREATEDB' ELSE 'NOCREATEDB' END || E'\n ' || + CASE WHEN rolcreaterole THEN 'CREATEROLE' ELSE 'NOCREATEROLE' END || E'\n ' || + -- PostgreSQL >= 9.1 + CASE WHEN rolreplication THEN 'REPLICATION' ELSE 'NOREPLICATION' END || E'\n ' || + CASE WHEN rolbypassrls THEN 'BYPASSRLS' ELSE 'NOBYPASSRLS' END || + CASE WHEN rolconnlimit > 0 THEN E'\n CONNECTION LIMIT ' || rolconnlimit ELSE '' END || +{% if show_password %} + (SELECT CASE + WHEN (rolpassword LIKE 'md5%%' or rolpassword LIKE 'SCRAM%%') THEN E'\n ENCRYPTED PASSWORD ''' || rolpassword || '''' + WHEN rolpassword IS NOT NULL THEN E'\n PASSWORD ''' || rolpassword || '''' + ELSE '' END FROM pg_catalog.pg_authid au WHERE au.oid=r.oid) || +{% endif %} + CASE WHEN rolvaliduntil IS NOT NULL THEN E'\n VALID UNTIL ' || pg_catalog.quote_literal(rolvaliduntil::text) ELSE '' END || ';' AS sql +FROM + pg_catalog.pg_roles r +WHERE + r.oid=%(rid)s::OID +UNION ALL +(SELECT + pg_catalog.array_to_string(array_agg(sql), E'\n') AS sql +FROM +(SELECT + 'GRANT ' || pg_catalog.array_to_string(pg_catalog.array_agg(rolname ORDER BY rolname), ', ') || ' TO ' || pg_catalog.quote_ident(pg_catalog.pg_get_userbyid(%(rid)s::OID)) || + CASE WHEN admin_option OR inherit_option OR set_option THEN + ' WITH ' || + (CASE WHEN admin_option THEN 'ADMIN OPTION' ELSE '' END || + CASE WHEN inherit_option THEN (CASE WHEN admin_option THEN ', ' ELSE '' END) || 'INHERIT OPTION' ELSE '' END || + CASE WHEN set_option THEN (CASE WHEN admin_option OR inherit_option THEN ', ' ELSE '' END) || 'SET OPTION' ELSE '' END) + ELSE '' END || ';' AS sql +FROM + (SELECT + pg_catalog.quote_ident(r.rolname) AS rolname, + m.admin_option AS admin_option, + m.inherit_option AS inherit_option, + m.set_option AS set_option + FROM + pg_catalog.pg_auth_members m + LEFT JOIN pg_catalog.pg_roles r ON (m.roleid = r.oid) + WHERE + m.member=%(rid)s::OID + ORDER BY + r.rolname + ) a +GROUP BY admin_option, inherit_option, set_option) s) +UNION ALL +(SELECT + pg_catalog.array_to_string(array_agg(sql), E'\n') AS sql +FROM +(SELECT + 'ALTER ROLE ' || pg_catalog.quote_ident(rolname) || ' SET ' || param || ' TO ' || CASE WHEN param IN ('search_path', 'temp_tablespaces') THEN value ELSE pg_catalog.quote_literal(value) END || ';' AS sql +FROM +(SELECT + rolcanlogin, rolname, pg_catalog.split_part(rolconfig, '=', 1) AS param, pg_catalog.replace(rolconfig, pg_catalog.split_part(rolconfig, '=', 1) || '=', '') AS value +FROM + (SELECT + pg_catalog.unnest(rolconfig) AS rolconfig, rolcanlogin, rolname + FROM + pg_catalog.pg_roles + WHERE + oid=%(rid)s::OID + ) r +) a) b) +-- PostgreSQL >= 9.0 +UNION ALL +(SELECT + pg_catalog.array_to_string(array_agg(sql), E'\n') AS sql +FROM + (SELECT + 'ALTER ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(%(rid)s::OID)) || + ' IN DATABASE ' || pg_catalog.quote_ident(datname) || + ' SET ' || param|| ' TO ' || + CASE + WHEN param IN ('search_path', 'temp_tablespaces') THEN value + ELSE pg_catalog.quote_literal(value) + END || ';' AS sql + FROM + (SELECT + datname, pg_catalog.split_part(rolconfig, '=', 1) AS param, pg_catalog.replace(rolconfig, pg_catalog.split_part(rolconfig, '=', 1) || '=', '') AS value + FROM + (SELECT + d.datname, pg_catalog.unnest(c.setconfig) AS rolconfig + FROM + (SELECT * + FROM + pg_catalog.pg_db_role_setting dr + WHERE + dr.setrole=%(rid)s::OID AND dr.setdatabase!=0) c + LEFT JOIN pg_catalog.pg_database d ON (d.oid = c.setdatabase) + ) a + ) b + ) d +) +UNION ALL +(SELECT + 'COMMENT ON ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(%(rid)s::OID)) || ' IS ' || pg_catalog.quote_literal(description) || ';' AS sql +FROM + (SELECT pg_catalog.shobj_description(%(rid)s::OID, 'pg_authid') AS description) a +WHERE + description IS NOT NULL) +-- PostgreSQL >= 9.2 +UNION ALL +(SELECT + pg_catalog.array_to_string(array_agg(sql), E'\n') AS sql +FROM + (SELECT + 'SECURITY LABEL FOR ' || provider || + E'\n ON ROLE ' || pg_catalog.quote_ident(rolname) || + E'\n IS ' || pg_catalog.quote_literal(label) || ';' AS sql + FROM + (SELECT + label, provider, rolname + FROM + (SELECT * + FROM + pg_catalog.pg_shseclabel sl1 + WHERE sl1.objoid=%(rid)s::OID) s + LEFT JOIN pg_catalog.pg_roles r ON (s.objoid=r.oid)) a) b +)) AS a diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/update.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/update.sql new file mode 100644 index 00000000000..a9c3d1b054f --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/16_plus/update.sql @@ -0,0 +1,119 @@ +{% import 'macros/security.macros' as SECLABEL %} +{% import 'macros/variable.macros' as VARIABLE %} +{% if 'rolname' in data %} +{% set rolname=data.rolname %} +ALTER ROLE {{ conn|qtIdent(role) }} + RENAME TO {{ conn|qtIdent(rolname) }}; + +{% else %} +{% set rolname=role %} +{% endif %} +{% if data|hasAny(alterKeys) %} +ALTER ROLE {{ conn|qtIdent(rolname) }}{% if 'rolcanlogin' in data %} + +{% if data.rolcanlogin %} + LOGIN{% else %} + NOLOGIN{% endif %}{% endif %}{% if 'rolsuper' in data %} + +{% if data.rolsuper %} + SUPERUSER{% else %} + NOSUPERUSER{% endif %}{% endif %}{% if 'rolcreatedb' in data %} + +{% if data.rolcreatedb %} + CREATEDB{% else %} + NOCREATEDB{% endif %}{% endif %}{% if 'rolcreaterole' in data %} + +{% if data.rolcreaterole %} + CREATEROLE{% else %} + NOCREATEROLE{% endif %}{% endif %}{% if 'rolinherit' in data %} + +{% if data.rolinherit %} + INHERIT{% else %} + NOINHERIT{% endif %}{% endif %}{% if 'rolreplication' in data %} + +{% if data.rolreplication %} + REPLICATION{% else %} + NOREPLICATION{% endif %}{% endif %}{% if 'rolbypassrls' in data %} + +{% if data.rolbypassrls %} + BYPASSRLS{% else %} + NOBYPASSRLS{% endif %}{% endif %}{% if 'rolconnlimit' in data and data.rolconnlimit is number and data.rolconnlimit >= -1 %} + + CONNECTION LIMIT {{ data.rolconnlimit }} +{% endif %}{% if 'rolvaliduntil' in data %} + + VALID UNTIL {% if data.rolvaliduntil %}{{ data.rolvaliduntil|qtLiteral(conn) }}{% else %}'infinity' +{% endif %}{% endif %}{% if 'rolpassword' in data %} + + PASSWORD{% if data.rolpassword is none %} NULL{% else %}{% if dummy %} 'xxxxxx'{% else %} {{ data.rolpassword|qtLiteral(conn) }}{% endif %}{% endif %}{% endif %};{% endif %} + +{% if data.rolmembership_revoked_list and data.rolmembership_revoked_list|length > 0 %} +{% for item in data.rolmembership_revoked_list %} + +REVOKE {{ conn|qtIdent(item.role) }} FROM {{ conn|qtIdent(rolname) }}; +{% endfor %} +{% endif %} +{% if data.rolmembership_list and data.rolmembership_list|length > 0 %} +{% for item in data.rolmembership_list %} + +GRANT {{ conn|qtIdent(item.role) }} TO {{ conn|qtIdent(rolname) }}{% if 'admin' in item or 'inherit' in item or 'set' in item %} WITH ADMIN {{ item.admin }}, INHERIT {{ item.inherit }}, SET {{ item.set }}{% endif %}; +{% endfor %} +{% endif %} +{% if data.seclabels and + data.seclabels|length > 0 +%}{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} + +{% for r in seclabels.deleted %} +{{ SECLABEL.DROP(conn, 'ROLE', rolname, r.provider) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} + +{% for r in seclabels.added %} +{{ SECLABEL.APPLY(conn, 'ROLE', rolname, r.provider, r.label) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} + +{% for r in seclabels.changed %} +{{ SECLABEL.APPLY(conn, 'ROLE', rolname, r.provider, r.label) }} +{% endfor %} +{% endif %} +{% endif %} +{% if 'variables' in data and data.variables|length > 0 %} +{% set variables = data.variables %} +{% if 'deleted' in variables and variables.deleted|length > 0 %} + +{% for var in variables.deleted %} +{{ VARIABLE.RESET(conn, var.database, rolname, var.name) }} +{% endfor %}{% endif %} +{% if 'added' in variables and variables.added|length > 0 %} + +{% for var in variables.added %} +{{ VARIABLE.APPLY(conn, var.database, rolname, var.name, var.value) }} +{% endfor %}{% endif %} +{% if 'changed' in variables and variables.changed|length > 0 %} + +{% for var in variables.changed %} +{{ VARIABLE.APPLY(conn, var.database, rolname, var.name, var.value) }} +{% endfor %} +{% endif %} +{% endif %} +{% if 'description' in data %} + + +COMMENT ON ROLE {{ conn|qtIdent(rolname) }} IS {{ data.description|qtLiteral(conn) }}; +{% endif %} +{% if data.rol_members_revoked_list and data.rol_members_revoked_list|length > 0 %} +{% for item in data.rol_members_revoked_list %} + +REVOKE {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(item.role) }}; +{% endfor %} +{% endif %} +{% if data.rol_members_list and data.rol_members_list|length > 0 %} +{% for item in data.rol_members_list %} + +GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(item.role) }} {% if 'admin' in item or 'inherit' in item or 'set' in item %} WITH ADMIN {{ item.admin }}, INHERIT {{ item.inherit }}, SET {{ item.set }}{% endif %}; +{% endfor %} +{% endif %} \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/create.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/create.sql index b2957c45020..90b983c8e22 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/create.sql +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/create.sql @@ -34,13 +34,14 @@ CREATE ROLE {{ conn|qtIdent(data.rolname) }} WITH{% if data.rolcanlogin and data VALID UNTIL {{ data.rolvaliduntil|qtLiteral(conn) }} {% endif %}{% if data.rolpassword %} - PASSWORD {% if data.rolpassword is none %}NULL{% else %}{% if dummy %}'xxxxxx'{% else %} {{ data.rolpassword|qtLiteral(conn) }}{% endif %}{% endif %}{% endif %};{% if data.members and data.members|length > 0 %} - - -GRANT {{ conn|qtIdent(data.members)|join(', ') }} TO {{ conn|qtIdent(data.rolname) }};{% endif %}{% if data.admins and data.admins|length > 0 %} - -GRANT {{ conn|qtIdent(data.admins)|join(', ') }} TO {{ conn|qtIdent(data.rolname) }} WITH ADMIN OPTION;{% endif %}{% if data.seclabels and data.seclabels|length > 0 %} + PASSWORD {% if data.rolpassword is none %}NULL{% else %}{% if dummy %}'xxxxxx'{% else %} {{ data.rolpassword|qtLiteral(conn) }}{% endif %}{% endif %}{% endif %}; +{% if data.rolmembership_list and data.rolmembership_list|length > 0 %} +{% for item in data.rolmembership_list %} +GRANT {{ conn|qtIdent(item.role) }} TO {{ conn|qtIdent(data.rolname) }}{% if 'admin' in item and item.admin %} WITH ADMIN OPTION{% endif %}; +{% endfor %} +{% endif %} +{% if data.seclabels and data.seclabels|length > 0 %} {% for r in data.seclabels %} {{ SECLABEL.APPLY(conn, 'ROLE', data.rolname, r.provider, r.label) }} @@ -53,10 +54,9 @@ GRANT {{ conn|qtIdent(data.admins)|join(', ') }} TO {{ conn|qtIdent(data.rolname COMMENT ON ROLE {{ conn|qtIdent(data.rolname) }} IS {{ data.description|qtLiteral(conn) }}; {% endif %} +{% if data.rol_members_list and data.rol_members_list|length > 0 %} +{% for item in data.rol_members_list %} -{% if data.rol_admins and data.rol_admins|length > 0 %} - -GRANT {{ conn|qtIdent(data.rolname) }} TO {{ conn|qtIdent(data.rol_admins)|join(', ') }} WITH ADMIN OPTION;{% endif %}{% if data.rol_members and data.rol_members|length > 0 %} - -GRANT {{ conn|qtIdent(data.rolname) }} TO {{ conn|qtIdent(data.rol_members)|join(', ') }}; +GRANT {{ conn|qtIdent(data.rolname) }} TO {{ conn|qtIdent(item.role) }}{% if 'admin' in item and item.admin %} WITH ADMIN OPTION{% endif %}; +{% endfor %} {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/update.sql b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/update.sql index 8f9daf10d7f..e6d12f8dd05 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/update.sql +++ b/web/pgadmin/browser/server_groups/servers/roles/templates/roles/sql/default/update.sql @@ -47,17 +47,27 @@ ALTER ROLE {{ conn|qtIdent(rolname) }}{% if 'rolcanlogin' in data %} PASSWORD{% if data.rolpassword is none %} NULL{% else %}{% if dummy %} 'xxxxxx'{% else %} {{ data.rolpassword|qtLiteral(conn) }}{% endif %}{% endif %}{% endif %};{% endif %} -{% if 'revoked_admins' in data and - data.revoked_admins|length > 0 -%} +{% if data.rolmembership_revoked_list and data.rolmembership_revoked_list|length > 0 %} +{% for item in data.rolmembership_revoked_list %} -REVOKE ADMIN OPTION FOR {{ conn|qtIdent(data.revoked_admins)|join(', ') }} FROM {{ conn|qtIdent(rolname) }};{% endif %}{% if 'revoked' in data and data.revoked|length > 0 %} - -REVOKE {{ conn|qtIdent(data.revoked)|join(', ') }} FROM {{ conn|qtIdent(rolname) }};{% endif %}{% if data.admins and data.admins|length > 0 %} +REVOKE {{ conn|qtIdent(item.role) }} FROM {{ conn|qtIdent(rolname) }}; +{% endfor %} +{% endif %} +{% if data.rolmembership_list and data.rolmembership_list|length > 0 %} +{% for item in data.rolmembership_list %} -GRANT {{ conn|qtIdent(data.admins)|join(', ') }} TO {{ conn|qtIdent(rolname) }} WITH ADMIN OPTION;{% endif %}{% if data.members and data.members|length > 0 %} +GRANT {{ conn|qtIdent(item.role) }} TO {{ conn|qtIdent(rolname) }}{% if 'admin' in item and item.admin %} WITH ADMIN OPTION{% endif %}; +{% endfor %} +{% endif %} +{% if data.rolmembership_revoked_admins and data.rolmembership_revoked_admins|length > 0 %} +{% for item in data.rolmembership_revoked_admins %} +{% if 'admin' in item and not item.admin %} -GRANT {{ conn|qtIdent(data.members)|join(', ') }} TO {{ conn|qtIdent(rolname) }};{% endif %}{% if data.seclabels and +REVOKE ADMIN OPTION FOR {{ conn|qtIdent(item.role) }} FROM {{ conn|qtIdent(rolname) }}; +{% endif %} +{% endfor %} +{% endif %} +{% if data.seclabels and data.seclabels|length > 0 %}{% set seclabels = data.seclabels %} {% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} @@ -103,15 +113,23 @@ GRANT {{ conn|qtIdent(data.members)|join(', ') }} TO {{ conn|qtIdent(rolname) }} COMMENT ON ROLE {{ conn|qtIdent(rolname) }} IS {{ data.description|qtLiteral(conn) }}; {% endif %} +{% if data.rol_members_revoked_list and data.rol_members_revoked_list|length > 0 %} +{% for item in data.rol_members_revoked_list %} -{% if 'rol_revoked_admins' in data and - data.rol_revoked_admins|length > 0 -%} - -REVOKE ADMIN OPTION FOR {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked_admins)|join(', ') }};{% endif %}{% if 'rol_revoked' in data and data.rol_revoked|length > 0 %} - -REVOKE {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(data.rol_revoked)|join(', ') }};{% endif %}{% if data.rol_admins and data.rol_admins|length > 0 %} +REVOKE {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(item.role) }}; +{% endfor %} +{% endif %} +{% if data.rol_members_list and data.rol_members_list|length > 0 %} +{% for item in data.rol_members_list %} -GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_admins)|join(', ') }} WITH ADMIN OPTION;{% endif %}{% if data.rol_members and data.rol_members|length > 0 %} +GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(item.role) }}{% if 'admin' in item and item.admin %} WITH ADMIN OPTION{% endif %}; +{% endfor %} +{% endif %} +{% if data.rol_members_revoked_admins and data.rol_members_revoked_admins|length > 0 %} +{% for item in data.rol_members_revoked_admins %} +{% if 'admin' in item and not item.admin %} -GRANT {{ conn|qtIdent(rolname) }} TO {{ conn|qtIdent(data.rol_members)|join(', ') }};{% endif %} +REVOKE ADMIN OPTION FOR {{ conn|qtIdent(rolname) }} FROM {{ conn|qtIdent(item.role) }}; +{% endif %} +{% endfor %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.msql new file mode 100644 index 00000000000..0abf435055e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.msql @@ -0,0 +1 @@ +COMMENT ON ROLE "Role1_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.sql new file mode 100644 index 00000000000..c8f16a31691 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_description.sql @@ -0,0 +1,13 @@ +-- Role: "Role1_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role1_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + LOGIN + SUPERUSER + INHERIT + CREATEDB + CREATEROLE + REPLICATION + BYPASSRLS; + +COMMENT ON ROLE "Role1_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.msql new file mode 100644 index 00000000000..088b078346c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.msql @@ -0,0 +1,2 @@ +ALTER ROLE "Role1_$%{}[]()&*^!@""'`\/#" + RENAME TO "Role2_$%{}[]()&*^!@""'`\/#"; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.sql new file mode 100644 index 00000000000..be6a483098c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_name.sql @@ -0,0 +1,13 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + LOGIN + SUPERUSER + INHERIT + CREATEDB + CREATEROLE + REPLICATION + BYPASSRLS; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.msql new file mode 100644 index 00000000000..92c0d420134 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.msql @@ -0,0 +1,12 @@ +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" + NOSUPERUSER + NOCREATEDB + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + + VALID UNTIL '2050-01-01T00:00:00+05:30' + PASSWORD 'xxxxxx'; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres + SET application_name TO 'pg4'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.sql new file mode 100644 index 00000000000..ce772b96016 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_login_role_options.sql @@ -0,0 +1,18 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + LOGIN + NOSUPERUSER + INHERIT + NOCREATEDB + CREATEROLE + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + ENCRYPTED PASSWORD '' + VALID UNTIL ''; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.msql new file mode 100644 index 00000000000..0abf435055e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.msql @@ -0,0 +1 @@ +COMMENT ON ROLE "Role1_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.sql new file mode 100644 index 00000000000..67279efd1f6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_description.sql @@ -0,0 +1,13 @@ +-- Role: "Role1_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role1_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + NOSUPERUSER + INHERIT + NOCREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS; + +COMMENT ON ROLE "Role1_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.msql new file mode 100644 index 00000000000..088b078346c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.msql @@ -0,0 +1,2 @@ +ALTER ROLE "Role1_$%{}[]()&*^!@""'`\/#" + RENAME TO "Role2_$%{}[]()&*^!@""'`\/#"; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.sql new file mode 100644 index 00000000000..604676c7d13 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_name.sql @@ -0,0 +1,13 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + NOSUPERUSER + INHERIT + NOCREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.msql new file mode 100644 index 00000000000..c4e291b1c01 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.msql @@ -0,0 +1,19 @@ +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" + SUPERUSER + CREATEDB + NOREPLICATION + CONNECTION LIMIT 100 + + VALID UNTIL '2050-01-01T00:00:00+05:30' + PASSWORD 'xxxxxx'; + +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN True, INHERIT True, SET True; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN False, INHERIT False, SET False; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres + SET application_name TO 'pg4'; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_3 WITH ADMIN True, INHERIT True, SET True; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_4 WITH ADMIN False, INHERIT False, SET False; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.sql new file mode 100644 index 00000000000..f71dbbf8eb0 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options1.sql @@ -0,0 +1,21 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + SUPERUSER + INHERIT + CREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + ENCRYPTED PASSWORD '' + VALID UNTIL ''; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#"; +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION, INHERIT OPTION, SET OPTION; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.msql new file mode 100644 index 00000000000..8544090581a --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.msql @@ -0,0 +1,7 @@ +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN False, INHERIT False, SET False; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN True, INHERIT True, SET True; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_3 WITH ADMIN False, INHERIT False, SET False; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_4 WITH ADMIN True, INHERIT True, SET True; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.sql new file mode 100644 index 00000000000..b228f0e11a6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options2.sql @@ -0,0 +1,21 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + SUPERUSER + INHERIT + CREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + ENCRYPTED PASSWORD '' + VALID UNTIL '2050-01-01 00:00:00+05:30'; + +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#"; +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION, INHERIT OPTION, SET OPTION; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.msql new file mode 100644 index 00000000000..3de70e1dcb8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.msql @@ -0,0 +1,3 @@ +REVOKE test_rolemembership_1 FROM "Role2_$%{}[]()&*^!@""'`\/#"; + +REVOKE "Role2_$%{}[]()&*^!@""'`\/#" FROM test_rolemembership_3; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.sql new file mode 100644 index 00000000000..ca1f7e51ba8 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options3.sql @@ -0,0 +1,20 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + SUPERUSER + INHERIT + CREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + ENCRYPTED PASSWORD '' + VALID UNTIL '2050-01-01 00:00:00+05:30'; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION, INHERIT OPTION, SET OPTION; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.msql new file mode 100644 index 00000000000..447b2ef596e --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.msql @@ -0,0 +1,7 @@ +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN True, INHERIT True, SET True; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN False, INHERIT False, SET False; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_3 WITH ADMIN True, INHERIT True, SET True; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_4 WITH ADMIN False, INHERIT False, SET False; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.sql new file mode 100644 index 00000000000..d5a76eeda0d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/alter_role_options4.sql @@ -0,0 +1,21 @@ +-- Role: "Role2_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role2_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + SUPERUSER + INHERIT + CREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT 100 + ENCRYPTED PASSWORD '' + VALID UNTIL '2050-01-01 00:00:00+05:30'; + +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#"; +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION, INHERIT OPTION, SET OPTION; + +ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +COMMENT ON ROLE "Role2_$%{}[]()&*^!@""'`\/#" IS 'This is detailed description'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.msql new file mode 100644 index 00000000000..3ebaab48469 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.msql @@ -0,0 +1,9 @@ +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + LOGIN + SUPERUSER + CREATEDB + CREATEROLE + INHERIT + REPLICATION + BYPASSRLS + CONNECTION LIMIT -1; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.sql new file mode 100644 index 00000000000..2e408524778 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_login_role.sql @@ -0,0 +1,11 @@ +-- Role: "Role1_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role1_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + LOGIN + SUPERUSER + INHERIT + CREATEDB + CREATEROLE + REPLICATION + BYPASSRLS; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.msql new file mode 100644 index 00000000000..5d0c2026ece --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.msql @@ -0,0 +1,9 @@ +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + NOSUPERUSER + NOCREATEDB + NOCREATEROLE + INHERIT + NOREPLICATION + NOBYPASSRLS + CONNECTION LIMIT -1; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.sql new file mode 100644 index 00000000000..bf6054895eb --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/create_role.sql @@ -0,0 +1,11 @@ +-- Role: "Role1_$%{}[]()&*^!@""'`\/#" +-- DROP ROLE IF EXISTS "Role1_$%{}[]()&*^!@""'`\/#"; + +CREATE ROLE "Role1_$%{}[]()&*^!@""'`\/#" WITH + NOLOGIN + NOSUPERUSER + INHERIT + NOCREATEDB + NOCREATEROLE + NOREPLICATION + NOBYPASSRLS; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/test.json b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/test.json new file mode 100644 index 00000000000..bd1b249d340 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/16_plus/test.json @@ -0,0 +1,299 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Role 1 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_1", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Role 2 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_2", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Role 3 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_3", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Role 4 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_4", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Role", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql", + "data": { + "rolname": "Role1_$%{}[]()&*^!@\"'`\\/#", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "expected_sql_file": "create_role.sql", + "expected_msql_file": "create_role.msql" + }, + { + "type": "alter", + "name": "Alter Role description", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "description": "This is detailed description" + }, + "expected_sql_file": "alter_role_description.sql", + "expected_msql_file": "alter_role_description.msql" + }, + { + "type": "alter", + "name": "Alter Role name", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolname": "Role2_$%{}[]()&*^!@\"'`\\/#" + }, + "expected_sql_file": "alter_role_name.sql", + "expected_msql_file": "alter_role_name.msql" + }, + { + "type": "alter", + "name": "Alter Role options 1", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolsuper": true, + "rolcreatedb": true, + "rolreplication": false, + "rolpassword": "abc123", + "rolconnlimit": 100, + "rolvaliduntil": "2050-01-01 00:00:00 +05:30", + "variables": { "added": [{"name":"application_name","value":"pg4","database":"postgres"}] }, + "rolmembership": { "added": [{"role": "test_rolemembership_1", "admin": true, "inherit": true, "set": true}, {"role": "test_rolemembership_2", "admin": false, "inherit": false, "set": false}] }, + "rolmembers": { "added": [{"role": "test_rolemembership_3", "admin": true, "inherit": true, "set": true}, {"role": "test_rolemembership_4", "admin": false, "inherit": false, "set": false}] } + }, + "expected_sql_file": "alter_role_options1.sql", + "expected_msql_file": "alter_role_options1.msql", + "convert_timestamp_columns": ["rolvaliduntil"], + "replace_password": true + }, + { + "type": "alter", + "name": "Alter Role options 2", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolmembership": { "changed": [{"role": "test_rolemembership_1", "admin": false, "inherit": false, "set": false}, {"role": "test_rolemembership_2", "admin": true, "inherit": true, "set": true}] }, + "rolmembers": { "changed": [{"role": "test_rolemembership_3", "admin": false, "inherit": false, "set": false}, {"role": "test_rolemembership_4", "admin": true, "inherit": true, "set": true}] } + }, + "expected_sql_file": "alter_role_options2.sql", + "expected_msql_file": "alter_role_options2.msql", + "convert_timestamp_columns": ["rolvaliduntil"], + "replace_password": true, + "replace_regex_pattern": ["VALID UNTIL '[0-9\\-T:+ ]*'"] + }, + { + "type": "alter", + "name": "Alter Role options 3", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolmembership": { "deleted": [{"role": "test_rolemembership_1"}] }, + "rolmembers": { "deleted": [{"role": "test_rolemembership_3"}] } + }, + "expected_sql_file": "alter_role_options3.sql", + "expected_msql_file": "alter_role_options3.msql", + "convert_timestamp_columns": ["rolvaliduntil"], + "replace_password": true, + "replace_regex_pattern": ["VALID UNTIL '[0-9\\-T:+ ]*'"] + }, + { + "type": "alter", + "name": "Alter Role options 4", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolmembership": { + "added": [{"role": "test_rolemembership_1", "admin": true, "inherit": true, "set": true}], + "changed": [{"role": "test_rolemembership_2", "admin": false, "inherit": false, "set": false}] + }, + "rolmembers": { + "added": [{"role": "test_rolemembership_3", "admin": true, "inherit": true, "set": true}], + "changed": [{"role": "test_rolemembership_4", "admin": false, "inherit": false, "set": false}] + } + }, + "expected_sql_file": "alter_role_options4.sql", + "expected_msql_file": "alter_role_options4.msql", + "convert_timestamp_columns": ["rolvaliduntil"], + "replace_password": true, + "replace_regex_pattern": ["VALID UNTIL '[0-9\\-T:+ ]*'"] + }, + { + "type": "delete", + "name": "Drop Role", + "endpoint": "NODE-role.obj_id", + "data": {} + }, + { + "type": "delete", + "name": "Drop Role", + "endpoint": "NODE-role.obj", + "data": {"ids": ["", "", "", ""]}, + "preprocess_data": true + }, + { + "type": "create", + "name": "Create Login Role", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql", + "data": { + "rolname": "Role1_$%{}[]()&*^!@\"'`\\/#", + "rolcanlogin": true, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": true, + "rolcreaterole": true, + "rolcreatedb": true, + "rolinherit": true, + "rolreplication": true, + "rolbypassrls": true, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "expected_sql_file": "create_login_role.sql", + "expected_msql_file": "create_login_role.msql" + }, + { + "type": "alter", + "name": "Alter Login Role description", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "description": "This is detailed description" + }, + "expected_sql_file": "alter_login_role_description.sql", + "expected_msql_file": "alter_login_role_description.msql" + }, + { + "type": "alter", + "name": "Alter Login Role name", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolname": "Role2_$%{}[]()&*^!@\"'`\\/#" + }, + "expected_sql_file": "alter_login_role_name.sql", + "expected_msql_file": "alter_login_role_name.msql" + }, + { + "type": "alter", + "name": "Alter Login Role options", + "endpoint": "NODE-role.obj_id", + "sql_endpoint": "NODE-role.sql_id", + "msql_endpoint": "NODE-role.msql_id", + "data": { + "rolsuper": false, + "rolcreatedb": false, + "rolreplication": false, + "rolbypassrls": false, + "rolpassword": "abc123", + "rolconnlimit": 100, + "rolvaliduntil": "2050-01-01 00:00:00 +05:30", + "variables": { "added": [{"name":"application_name","value":"pg4","database":"postgres"}] } + }, + "expected_sql_file": "alter_login_role_options.sql", + "expected_msql_file": "alter_login_role_options.msql", + "convert_timestamp_columns": ["rolvaliduntil"], + "replace_password": true + }, + { + "type": "delete", + "name": "Drop Login Role", + "endpoint": "NODE-role.obj_id", + "data": {} + } + ] +} diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options1.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options1.msql index cd6738440ca..a00fa578f07 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options1.msql +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options1.msql @@ -8,6 +8,12 @@ ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" PASSWORD 'xxxxxx'; GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; + GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#"; + ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_3 WITH ADMIN OPTION; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_4; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options2.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options2.msql index 06672e89378..94bd9637f16 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options2.msql +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options2.msql @@ -1,2 +1,7 @@ -REVOKE ADMIN OPTION FOR test_rolemembership_1 FROM "Role2_$%{}[]()&*^!@""'`\/#"; GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; + +REVOKE ADMIN OPTION FOR test_rolemembership_1 FROM "Role2_$%{}[]()&*^!@""'`\/#"; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_4 WITH ADMIN OPTION; + +REVOKE ADMIN OPTION FOR "Role2_$%{}[]()&*^!@""'`\/#" FROM test_rolemembership_3; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options3.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options3.msql index ab13abdd682..3de70e1dcb8 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options3.msql +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options3.msql @@ -1 +1,3 @@ REVOKE test_rolemembership_1 FROM "Role2_$%{}[]()&*^!@""'`\/#"; + +REVOKE "Role2_$%{}[]()&*^!@""'`\/#" FROM test_rolemembership_3; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.msql b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.msql index d987e1c7f0b..d900fe39c40 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.msql +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.msql @@ -1 +1,7 @@ -GRANT test_rolemembership_1, test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; + +REVOKE ADMIN OPTION FOR test_rolemembership_2 FROM "Role2_$%{}[]()&*^!@""'`\/#"; + +GRANT "Role2_$%{}[]()&*^!@""'`\/#" TO test_rolemembership_3 WITH ADMIN OPTION; + +REVOKE ADMIN OPTION FOR "Role2_$%{}[]()&*^!@""'`\/#" FROM test_rolemembership_4; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.sql b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.sql index 1814b956899..7ef7414768a 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.sql +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/alter_role_options4.sql @@ -13,7 +13,8 @@ CREATE ROLE "Role2_$%{}[]()&*^!@""'`\/#" WITH ENCRYPTED PASSWORD '' VALID UNTIL '2050-01-01 00:00:00+05:30'; -GRANT test_rolemembership_1, test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; +GRANT test_rolemembership_2 TO "Role2_$%{}[]()&*^!@""'`\/#"; +GRANT test_rolemembership_1 TO "Role2_$%{}[]()&*^!@""'`\/#" WITH ADMIN OPTION; ALTER ROLE "Role2_$%{}[]()&*^!@""'`\/#" IN DATABASE postgres SET application_name TO 'pg4'; diff --git a/web/pgadmin/browser/server_groups/servers/roles/tests/default/test.json b/web/pgadmin/browser/server_groups/servers/roles/tests/default/test.json index b5ea013e6cb..454a76abf6e 100644 --- a/web/pgadmin/browser/server_groups/servers/roles/tests/default/test.json +++ b/web/pgadmin/browser/server_groups/servers/roles/tests/default/test.json @@ -42,6 +42,48 @@ }, "store_object_id": true }, + { + "type": "create", + "name": "Create Role 3 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_3", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Role 4 for testing rolemembership", + "endpoint": "NODE-role.obj", + "sql_endpoint": "NODE-role.sql_id", + "data": { + "rolname": "test_rolemembership_4", + "rolcanlogin": false, + "rolpassword": null, + "rolconnlimit": -1, + "rolsuper": false, + "rolcreaterole": false, + "rolcreatedb": false, + "rolinherit": true, + "rolreplication": false, + "rolmembership": [], + "seclabels": [], + "variables": [] + }, + "store_object_id": true + }, { "type": "create", "name": "Create Role", @@ -103,7 +145,8 @@ "rolconnlimit": 100, "rolvaliduntil": "2050-01-01 00:00:00 +05:30", "variables": { "added": [{"name":"application_name","value":"pg4","database":"postgres"}] }, - "rolmembership": { "added": [{"role": "test_rolemembership_1", "admin": true}, {"role": "test_rolemembership_2", "admin": false}] } + "rolmembership": { "added": [{"role": "test_rolemembership_1", "admin": true}, {"role": "test_rolemembership_2", "admin": false}] }, + "rolmembers": { "added": [{"role": "test_rolemembership_3", "admin": true}, {"role": "test_rolemembership_4", "admin": false}] } }, "expected_sql_file": "alter_role_options1.sql", "expected_msql_file": "alter_role_options1.msql", @@ -117,7 +160,8 @@ "sql_endpoint": "NODE-role.sql_id", "msql_endpoint": "NODE-role.msql_id", "data": { - "rolmembership": { "changed": [{"role": "test_rolemembership_1", "admin": false}, {"role": "test_rolemembership_2", "admin": true}] } + "rolmembership": { "changed": [{"role": "test_rolemembership_1", "admin": false}, {"role": "test_rolemembership_2", "admin": true}] }, + "rolmembers": { "changed": [{"role": "test_rolemembership_3", "admin": false}, {"role": "test_rolemembership_4", "admin": true}] } }, "expected_sql_file": "alter_role_options2.sql", "expected_msql_file": "alter_role_options2.msql", @@ -132,7 +176,8 @@ "sql_endpoint": "NODE-role.sql_id", "msql_endpoint": "NODE-role.msql_id", "data": { - "rolmembership": { "deleted": [{"role": "test_rolemembership_1"}] } + "rolmembership": { "deleted": [{"role": "test_rolemembership_1"}] }, + "rolmembers": { "deleted": [{"role": "test_rolemembership_3"}] } }, "expected_sql_file": "alter_role_options3.sql", "expected_msql_file": "alter_role_options3.msql", @@ -149,7 +194,11 @@ "data": { "rolmembership": { "added": [{"role": "test_rolemembership_1", "admin": true}], - "changed": [{"role": "test_rolemembership_2", "admin": true}] + "changed": [{"role": "test_rolemembership_2", "admin": false}] + }, + "rolmembers": { + "added": [{"role": "test_rolemembership_3", "admin": true}], + "changed": [{"role": "test_rolemembership_4", "admin": false}] } }, "expected_sql_file": "alter_role_options4.sql", @@ -168,7 +217,7 @@ "type": "delete", "name": "Drop Role", "endpoint": "NODE-role.obj", - "data": {"ids": ["", ""]}, + "data": {"ids": ["", "", "", ""]}, "preprocess_data": true }, { diff --git a/web/pgadmin/browser/server_groups/servers/static/js/membership.ui.js b/web/pgadmin/browser/server_groups/servers/static/js/membership.ui.js index 81bb7cf9600..aad9f4fdea9 100644 --- a/web/pgadmin/browser/server_groups/servers/static/js/membership.ui.js +++ b/web/pgadmin/browser/server_groups/servers/static/js/membership.ui.js @@ -15,15 +15,18 @@ import { getNodeListByName } from '../../../../static/js/node_ajax'; export function getMembershipSchema(nodeObj, treeNodeInfo, itemNodeData) { return new MembershipSchema( ()=>getNodeListByName('role', treeNodeInfo, itemNodeData, {}, ()=>true), + treeNodeInfo.server ); } export default class MembershipSchema extends BaseUISchema { - constructor(roleMembersOptions) { + constructor(roleMembersOptions, node_info={}) { super({ role: undefined, - admin: undefined + admin: (node_info) && node_info.version >= 160000 ? false : undefined, + inherit: undefined, + set: (node_info) && node_info.version >= 160000 ? true : undefined, }); this.roleMembersOptions = roleMembersOptions; } @@ -43,18 +46,38 @@ export default class MembershipSchema extends BaseUISchema { return !obj.isNew(state); }, noEmpty: true, - minWidth: 300 + width: 150 }, { id: 'admin', label: gettext('WITH ADMIN'), cell: 'checkbox', type: 'checkbox', - minWidth: 300, + minWidth: 100, deps: ['role'], depChange: (state) => { if(_.isUndefined(state.admin)) { state.admin = false; } } + },{ + id: 'inherit', label: gettext('WITH INHERIT'), + cell: 'checkbox', type: 'checkbox', + minWidth: 100, min_version: 160000, + deps: ['role'], + depChange: (state) => { + if(_.isUndefined(state.inherit)) { + state.inherit = false; + } + } + },{ + id: 'set', label: gettext('WITH SET'), + cell: 'checkbox', type: 'checkbox', + minWidth: 100, min_version: 160000, + deps: ['role'], + depChange: (state) => { + if(_.isUndefined(state.set)) { + state.set = true; + } + } }, ]; } diff --git a/web/pgadmin/static/js/SchemaView/DataGridView/utils/createGridColumns.jsx b/web/pgadmin/static/js/SchemaView/DataGridView/utils/createGridColumns.jsx index 21c258ee85f..917997cdd11 100644 --- a/web/pgadmin/static/js/SchemaView/DataGridView/utils/createGridColumns.jsx +++ b/web/pgadmin/static/js/SchemaView/DataGridView/utils/createGridColumns.jsx @@ -8,7 +8,7 @@ ////////////////////////////////////////////////////////////// -import { isModeSupportedByField } from 'sources/SchemaView/common'; +import { isModeSupportedByField, isFieldSupportedByPgVersion } from 'sources/SchemaView/common'; import { getMappedCell } from '../mappedCell'; @@ -49,7 +49,7 @@ export function createGridColumns({schema, field, viewHelperProps}) { ); columnVisibility[field.id] = isModeSupportedByField( field, viewHelperProps - ); + ) && isFieldSupportedByPgVersion(field, viewHelperProps); return { header: field.label||<> , diff --git a/web/pgadmin/static/js/SchemaView/common.js b/web/pgadmin/static/js/SchemaView/common.js index 0cd026e54ad..f4bd0ad7aba 100644 --- a/web/pgadmin/static/js/SchemaView/common.js +++ b/web/pgadmin/static/js/SchemaView/common.js @@ -16,6 +16,22 @@ export const isModeSupportedByField = (field, helperProps) => ( !field.mode || field.mode.indexOf(helperProps.mode) > -1 ); +export const isFieldSupportedByPgVersion = (field, helperProps) => { + return ( + // serverInfo not found + _.isUndefined(helperProps.serverInfo) || + // serverInfo found and it's within range + ( + _.isUndefined(field.server_type) ? true : + (helperProps.serverInfo.type in field.server_type) + ) && ( + _.isUndefined(field.min_version) ? true : + (helperProps.serverInfo.version >= field.min_version) + ) && ( + _.isUndefined(field.max_version) ? true : + (helperProps.serverInfo.version <= field.max_version) + )); +}; /* * Compare the sessData with schema.origData. diff --git a/web/pgadmin/static/js/SchemaView/options/index.js b/web/pgadmin/static/js/SchemaView/options/index.js index 7772d8c27bf..07e73ba4351 100644 --- a/web/pgadmin/static/js/SchemaView/options/index.js +++ b/web/pgadmin/static/js/SchemaView/options/index.js @@ -15,6 +15,10 @@ import { evalInNonPropertyMode, FIELD_OPTIONS } from './common'; +import { + isFieldSupportedByPgVersion, + isModeSupportedByField +} from '../common'; import { evaluateFieldOptions, evaluateFieldsOption, @@ -45,23 +49,9 @@ registerOptionEvaluator( VISIBLE, // Evaluator ({schema, field, value, viewHelperProps}) => ( - ( - !field.mode || field.mode.indexOf(viewHelperProps.mode) > -1 - ) && ( - // serverInfo not found - _.isUndefined(viewHelperProps.serverInfo) || - // serverInfo found and it's within range - (( - _.isUndefined(field.server_type) ? true : - (viewHelperProps.serverInfo.type in field.server_type) - ) && ( - _.isUndefined(field.min_version) ? true : - (viewHelperProps.serverInfo.version >= field.min_version) - ) && ( - _.isUndefined(field.max_version) ? true : - (viewHelperProps.serverInfo.version <= field.max_version) - )) - ) && ( + isModeSupportedByField(field, viewHelperProps) + && isFieldSupportedByPgVersion(field, viewHelperProps) + && ( _.isUndefined(field[VISIBLE]) ? true : Boolean(evalFunc(schema, field[VISIBLE], value)) )),