From 2fd69c860c08805f9aaf25f375d952991cd45e00 Mon Sep 17 00:00:00 2001
From: Mark Dilger <mark.dilger@enterprisedb.com>
Date: Tue, 4 Jan 2022 10:35:10 -0800
Subject: [PATCH v4 1/5] Add tests of the CREATEROLE attribute.

While developing alternate rules for what privileges CREATEROLE has,
I noticed that none of the changes to how CREATEROLE works triggered
any regression test failures.  This is problematic for two reasons.
It means the existing code has insufficient test coverage, and it
means that unintended changes introduced by subsequent patches may
go unnoticed.  Fix that.
---
 src/test/regress/expected/create_role.out | 145 ++++++++++++++++++++++
 src/test/regress/parallel_schedule        |   2 +-
 src/test/regress/sql/create_role.sql      | 138 ++++++++++++++++++++
 3 files changed, 284 insertions(+), 1 deletion(-)
 create mode 100644 src/test/regress/expected/create_role.out
 create mode 100644 src/test/regress/sql/create_role.sql

diff --git a/src/test/regress/expected/create_role.out b/src/test/regress/expected/create_role.out
new file mode 100644
index 0000000000..57010bbb58
--- /dev/null
+++ b/src/test/regress/expected/create_role.out
@@ -0,0 +1,145 @@
+-- ok, superuser can create users with any set of privileges
+CREATE ROLE regress_role_super SUPERUSER;
+CREATE ROLE regress_role_1 CREATEDB CREATEROLE REPLICATION BYPASSRLS;
+-- fail, only superusers can create users with these privileges
+SET SESSION AUTHORIZATION regress_role_1;
+CREATE ROLE regress_role_2 SUPERUSER;
+ERROR:  must be superuser to create superusers
+CREATE ROLE regress_role_3 REPLICATION BYPASSRLS;
+ERROR:  must be superuser to create replication users
+CREATE ROLE regress_role_4 REPLICATION;
+ERROR:  must be superuser to create replication users
+CREATE ROLE regress_role_5 BYPASSRLS;
+ERROR:  must be superuser to create bypassrls users
+-- ok, having CREATEROLE is enough to create users with these privileges
+CREATE ROLE regress_role_6 CREATEDB;
+CREATE ROLE regress_role_7 CREATEROLE;
+CREATE ROLE regress_role_8 LOGIN;
+CREATE ROLE regress_role_9 INHERIT;
+CREATE ROLE regress_role_10 CONNECTION LIMIT 5;
+CREATE ROLE regress_role_11 ENCRYPTED PASSWORD 'foo';
+CREATE ROLE regress_role_12 PASSWORD NULL;
+-- ok, backwards compatible noise words should be ignored
+CREATE ROLE regress_role_13 SYSID 12345;
+NOTICE:  SYSID can no longer be specified
+-- fail, cannot grant membership in superuser role
+CREATE ROLE regress_role_14 IN ROLE regress_role_super;
+ERROR:  must be superuser to alter superusers
+-- fail, database owner cannot have members
+CREATE ROLE regress_role_15 IN ROLE pg_database_owner;
+ERROR:  role "pg_database_owner" cannot have explicit members
+-- ok, can grant other users into a role
+CREATE ROLE regress_role_16 ROLE
+	regress_role_super, regress_role_6, regress_role_7, regress_role_8,
+	regress_role_9, regress_role_10, regress_role_11, regress_role_12;
+-- fail, cannot grant a role into itself
+CREATE ROLE regress_role_17 ROLE regress_role_17;
+ERROR:  role "regress_role_17" is a member of role "regress_role_17"
+-- ok, can grant other users into a role with admin option
+CREATE ROLE regress_role_18 ADMIN
+	regress_role_super, regress_role_6, regress_role_7, regress_role_8,
+	regress_role_9, regress_role_10, regress_role_11, regress_role_12;
+-- fail, cannot grant a role into itself with admin option
+CREATE ROLE regress_role_19 ADMIN regress_role_19;
+ERROR:  role "regress_role_19" is a member of role "regress_role_19"
+-- fail, regress_role_7 does not have CREATEDB privilege
+SET SESSION AUTHORIZATION regress_role_7;
+CREATE DATABASE regress_db_7;
+ERROR:  permission denied to create database
+-- ok, regress_role_7 can create new roles
+CREATE ROLE regress_role_20;
+-- ok, roles with CREATEROLE can create new roles with it
+CREATE ROLE regress_role_21 CREATEROLE;
+-- ok, roles with CREATEROLE can create new roles with privilege they lack
+CREATE ROLE regress_role_22 CREATEDB CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5;
+-- ok, regress_role_22 can create objects within the database
+SET SESSION AUTHORIZATION regress_role_22;
+CREATE TABLE regress_tbl_22 (i integer);
+CREATE INDEX regress_idx_22 ON regress_tbl_22(i);
+CREATE VIEW regress_view_22 AS SELECT * FROM pg_catalog.pg_class;
+REVOKE ALL PRIVILEGES ON regress_tbl_22 FROM PUBLIC;
+-- fail, these objects belonging to regress_role_22
+SET SESSION AUTHORIZATION regress_role_7;
+DROP INDEX regress_idx_22;
+ERROR:  must be owner of index regress_idx_22
+ALTER TABLE regress_tbl_22 ADD COLUMN t text;
+ERROR:  must be owner of table regress_tbl_22
+DROP TABLE regress_tbl_22;
+ERROR:  must be owner of table regress_tbl_22
+ALTER VIEW regress_view_22 OWNER TO regress_role_1;
+ERROR:  must be owner of view regress_view_22
+DROP VIEW regress_view_22;
+ERROR:  must be owner of view regress_view_22
+-- fail, cannot take ownership of these objects from regress_role_22
+REASSIGN OWNED BY regress_role_22 TO regress_role_7;
+ERROR:  permission denied to reassign objects
+-- ok, having CREATEROLE is enough to create roles in privileged roles
+CREATE ROLE regress_role_23 IN ROLE pg_read_all_data;
+CREATE ROLE regress_role_24 IN ROLE pg_write_all_data;
+CREATE ROLE regress_role_25 IN ROLE pg_monitor;
+CREATE ROLE regress_role_26 IN ROLE pg_read_all_settings;
+CREATE ROLE regress_role_27 IN ROLE pg_read_all_stats;
+CREATE ROLE regress_role_28 IN ROLE pg_stat_scan_tables;
+CREATE ROLE regress_role_29 IN ROLE pg_read_server_files;
+CREATE ROLE regress_role_30 IN ROLE pg_write_server_files;
+CREATE ROLE regress_role_31 IN ROLE pg_execute_server_program;
+CREATE ROLE regress_role_32 IN ROLE pg_signal_backend;
+-- fail, creation of these roles failed above so they do not now exist
+SET SESSION AUTHORIZATION regress_role_1;
+DROP ROLE regress_role_2;
+ERROR:  role "regress_role_2" does not exist
+DROP ROLE regress_role_3;
+ERROR:  role "regress_role_3" does not exist
+DROP ROLE regress_role_4;
+ERROR:  role "regress_role_4" does not exist
+DROP ROLE regress_role_5;
+ERROR:  role "regress_role_5" does not exist
+DROP ROLE regress_role_14;
+ERROR:  role "regress_role_14" does not exist
+DROP ROLE regress_role_15;
+ERROR:  role "regress_role_15" does not exist
+DROP ROLE regress_role_17;
+ERROR:  role "regress_role_17" does not exist
+DROP ROLE regress_role_19;
+ERROR:  role "regress_role_19" does not exist
+DROP ROLE regress_role_20;
+-- ok, should be able to drop non-superuser roles we created
+DROP ROLE regress_role_6;
+DROP ROLE regress_role_7;
+DROP ROLE regress_role_8;
+DROP ROLE regress_role_9;
+DROP ROLE regress_role_10;
+DROP ROLE regress_role_11;
+DROP ROLE regress_role_12;
+DROP ROLE regress_role_13;
+DROP ROLE regress_role_16;
+DROP ROLE regress_role_18;
+DROP ROLE regress_role_21;
+DROP ROLE regress_role_23;
+DROP ROLE regress_role_24;
+DROP ROLE regress_role_25;
+DROP ROLE regress_role_26;
+DROP ROLE regress_role_27;
+DROP ROLE regress_role_28;
+DROP ROLE regress_role_29;
+DROP ROLE regress_role_30;
+DROP ROLE regress_role_31;
+DROP ROLE regress_role_32;
+-- fail, role still owns database objects
+DROP ROLE regress_role_22;
+ERROR:  role "regress_role_22" cannot be dropped because some objects depend on it
+DETAIL:  owner of table regress_tbl_22
+owner of view regress_view_22
+-- fail, cannot drop ourself nor superusers
+DROP ROLE regress_role_super;
+ERROR:  must be superuser to drop superusers
+DROP ROLE regress_role_1;
+ERROR:  current user cannot be dropped
+-- ok
+RESET SESSION AUTHORIZATION;
+DROP INDEX regress_idx_22;
+DROP TABLE regress_tbl_22;
+DROP VIEW regress_view_22;
+DROP ROLE regress_role_22;
+DROP ROLE regress_role_1;
+DROP ROLE regress_role_super;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 5b0c73d7e3..861c30a73a 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -89,7 +89,7 @@ test: brin_bloom brin_multi
 # ----------
 # Another group of parallel tests
 # ----------
-test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort
+test: create_table_like alter_generic alter_operator misc async dbsize misc_functions sysviews tsrf tid tidscan tidrangescan collate.icu.utf8 incremental_sort create_role
 
 # rules cannot run concurrently with any test that creates
 # a view or rule in the public schema
diff --git a/src/test/regress/sql/create_role.sql b/src/test/regress/sql/create_role.sql
new file mode 100644
index 0000000000..e00893de4e
--- /dev/null
+++ b/src/test/regress/sql/create_role.sql
@@ -0,0 +1,138 @@
+-- ok, superuser can create users with any set of privileges
+CREATE ROLE regress_role_super SUPERUSER;
+CREATE ROLE regress_role_1 CREATEDB CREATEROLE REPLICATION BYPASSRLS;
+
+-- fail, only superusers can create users with these privileges
+SET SESSION AUTHORIZATION regress_role_1;
+CREATE ROLE regress_role_2 SUPERUSER;
+CREATE ROLE regress_role_3 REPLICATION BYPASSRLS;
+CREATE ROLE regress_role_4 REPLICATION;
+CREATE ROLE regress_role_5 BYPASSRLS;
+
+-- ok, having CREATEROLE is enough to create users with these privileges
+CREATE ROLE regress_role_6 CREATEDB;
+CREATE ROLE regress_role_7 CREATEROLE;
+CREATE ROLE regress_role_8 LOGIN;
+CREATE ROLE regress_role_9 INHERIT;
+CREATE ROLE regress_role_10 CONNECTION LIMIT 5;
+CREATE ROLE regress_role_11 ENCRYPTED PASSWORD 'foo';
+CREATE ROLE regress_role_12 PASSWORD NULL;
+
+-- ok, backwards compatible noise words should be ignored
+CREATE ROLE regress_role_13 SYSID 12345;
+
+-- fail, cannot grant membership in superuser role
+CREATE ROLE regress_role_14 IN ROLE regress_role_super;
+
+-- fail, database owner cannot have members
+CREATE ROLE regress_role_15 IN ROLE pg_database_owner;
+
+-- ok, can grant other users into a role
+CREATE ROLE regress_role_16 ROLE
+	regress_role_super, regress_role_6, regress_role_7, regress_role_8,
+	regress_role_9, regress_role_10, regress_role_11, regress_role_12;
+
+-- fail, cannot grant a role into itself
+CREATE ROLE regress_role_17 ROLE regress_role_17;
+
+-- ok, can grant other users into a role with admin option
+CREATE ROLE regress_role_18 ADMIN
+	regress_role_super, regress_role_6, regress_role_7, regress_role_8,
+	regress_role_9, regress_role_10, regress_role_11, regress_role_12;
+
+-- fail, cannot grant a role into itself with admin option
+CREATE ROLE regress_role_19 ADMIN regress_role_19;
+
+-- fail, regress_role_7 does not have CREATEDB privilege
+SET SESSION AUTHORIZATION regress_role_7;
+CREATE DATABASE regress_db_7;
+
+-- ok, regress_role_7 can create new roles
+CREATE ROLE regress_role_20;
+
+-- ok, roles with CREATEROLE can create new roles with it
+CREATE ROLE regress_role_21 CREATEROLE;
+
+-- ok, roles with CREATEROLE can create new roles with privilege they lack
+CREATE ROLE regress_role_22 CREATEDB CREATEROLE LOGIN INHERIT CONNECTION LIMIT 5;
+
+-- ok, regress_role_22 can create objects within the database
+SET SESSION AUTHORIZATION regress_role_22;
+CREATE TABLE regress_tbl_22 (i integer);
+CREATE INDEX regress_idx_22 ON regress_tbl_22(i);
+CREATE VIEW regress_view_22 AS SELECT * FROM pg_catalog.pg_class;
+REVOKE ALL PRIVILEGES ON regress_tbl_22 FROM PUBLIC;
+
+-- fail, these objects belonging to regress_role_22
+SET SESSION AUTHORIZATION regress_role_7;
+DROP INDEX regress_idx_22;
+ALTER TABLE regress_tbl_22 ADD COLUMN t text;
+DROP TABLE regress_tbl_22;
+ALTER VIEW regress_view_22 OWNER TO regress_role_1;
+DROP VIEW regress_view_22;
+
+-- fail, cannot take ownership of these objects from regress_role_22
+REASSIGN OWNED BY regress_role_22 TO regress_role_7;
+
+-- ok, having CREATEROLE is enough to create roles in privileged roles
+CREATE ROLE regress_role_23 IN ROLE pg_read_all_data;
+CREATE ROLE regress_role_24 IN ROLE pg_write_all_data;
+CREATE ROLE regress_role_25 IN ROLE pg_monitor;
+CREATE ROLE regress_role_26 IN ROLE pg_read_all_settings;
+CREATE ROLE regress_role_27 IN ROLE pg_read_all_stats;
+CREATE ROLE regress_role_28 IN ROLE pg_stat_scan_tables;
+CREATE ROLE regress_role_29 IN ROLE pg_read_server_files;
+CREATE ROLE regress_role_30 IN ROLE pg_write_server_files;
+CREATE ROLE regress_role_31 IN ROLE pg_execute_server_program;
+CREATE ROLE regress_role_32 IN ROLE pg_signal_backend;
+
+-- fail, creation of these roles failed above so they do not now exist
+SET SESSION AUTHORIZATION regress_role_1;
+DROP ROLE regress_role_2;
+DROP ROLE regress_role_3;
+DROP ROLE regress_role_4;
+DROP ROLE regress_role_5;
+DROP ROLE regress_role_14;
+DROP ROLE regress_role_15;
+DROP ROLE regress_role_17;
+DROP ROLE regress_role_19;
+DROP ROLE regress_role_20;
+
+-- ok, should be able to drop non-superuser roles we created
+DROP ROLE regress_role_6;
+DROP ROLE regress_role_7;
+DROP ROLE regress_role_8;
+DROP ROLE regress_role_9;
+DROP ROLE regress_role_10;
+DROP ROLE regress_role_11;
+DROP ROLE regress_role_12;
+DROP ROLE regress_role_13;
+DROP ROLE regress_role_16;
+DROP ROLE regress_role_18;
+DROP ROLE regress_role_21;
+DROP ROLE regress_role_23;
+DROP ROLE regress_role_24;
+DROP ROLE regress_role_25;
+DROP ROLE regress_role_26;
+DROP ROLE regress_role_27;
+DROP ROLE regress_role_28;
+DROP ROLE regress_role_29;
+DROP ROLE regress_role_30;
+DROP ROLE regress_role_31;
+DROP ROLE regress_role_32;
+
+-- fail, role still owns database objects
+DROP ROLE regress_role_22;
+
+-- fail, cannot drop ourself nor superusers
+DROP ROLE regress_role_super;
+DROP ROLE regress_role_1;
+
+-- ok
+RESET SESSION AUTHORIZATION;
+DROP INDEX regress_idx_22;
+DROP TABLE regress_tbl_22;
+DROP VIEW regress_view_22;
+DROP ROLE regress_role_22;
+DROP ROLE regress_role_1;
+DROP ROLE regress_role_super;
-- 
2.21.1 (Apple Git-122.3)

