diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
commit | 311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch) | |
tree | 0ec307299b1dada3701e42f4ca6eda57d708261e /src/test/modules/dummy_seclabel | |
parent | Initial commit. (diff) | |
download | postgresql-15-upstream.tar.xz postgresql-15-upstream.zip |
Adding upstream version 15.4.upstream/15.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/modules/dummy_seclabel')
-rw-r--r-- | src/test/modules/dummy_seclabel/.gitignore | 4 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/Makefile | 20 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/README | 41 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql | 8 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/dummy_seclabel.c | 63 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/dummy_seclabel.control | 4 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/expected/dummy_seclabel.out | 117 | ||||
-rw-r--r-- | src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql | 115 |
8 files changed, 372 insertions, 0 deletions
diff --git a/src/test/modules/dummy_seclabel/.gitignore b/src/test/modules/dummy_seclabel/.gitignore new file mode 100644 index 0000000..5dcb3ff --- /dev/null +++ b/src/test/modules/dummy_seclabel/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/dummy_seclabel/Makefile b/src/test/modules/dummy_seclabel/Makefile new file mode 100644 index 0000000..d93c964 --- /dev/null +++ b/src/test/modules/dummy_seclabel/Makefile @@ -0,0 +1,20 @@ +# src/test/modules/dummy_seclabel/Makefile + +MODULES = dummy_seclabel +PGFILEDESC = "dummy_seclabel - regression testing of the SECURITY LABEL statement" + +EXTENSION = dummy_seclabel +DATA = dummy_seclabel--1.0.sql + +REGRESS = dummy_seclabel + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/dummy_seclabel +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/dummy_seclabel/README b/src/test/modules/dummy_seclabel/README new file mode 100644 index 0000000..a3fcbd7 --- /dev/null +++ b/src/test/modules/dummy_seclabel/README @@ -0,0 +1,41 @@ +The dummy_seclabel module exists only to support regression testing of +the SECURITY LABEL statement. It is not intended to be used in production. + +Rationale +========= + +The SECURITY LABEL statement allows the user to assign security labels to +database objects; however, security labels can only be assigned when +specifically allowed by a loadable module, so this module is provided to +allow proper regression testing. + +Security label providers intended to be used in production will typically be +dependent on a platform-specific feature such as SELinux. This module is +platform-independent, and therefore better-suited to regression testing. + +Usage +===== + +Here's a simple example of usage: + +# postgresql.conf +shared_preload_libraries = 'dummy_seclabel' + +postgres=# CREATE TABLE t (a int, b text); +CREATE TABLE +postgres=# SECURITY LABEL ON TABLE t IS 'classified'; +SECURITY LABEL + +The dummy_seclabel module provides only four hardcoded +labels: unclassified, classified, +secret, and top secret. +It does not allow any other strings as security labels. + +These labels are not used to enforce access controls. They are only used +to check whether the SECURITY LABEL statement works as expected, +or not. + +Author +====== + +KaiGai Kohei <kaigai@ak.jp.nec.com> diff --git a/src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql b/src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql new file mode 100644 index 0000000..5f3cb5b --- /dev/null +++ b/src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql @@ -0,0 +1,8 @@ +/* src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION dummy_seclabel" to load this file. \quit + +CREATE FUNCTION dummy_seclabel_dummy() + RETURNS pg_catalog.void + AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/dummy_seclabel/dummy_seclabel.c b/src/test/modules/dummy_seclabel/dummy_seclabel.c new file mode 100644 index 0000000..67658c1 --- /dev/null +++ b/src/test/modules/dummy_seclabel/dummy_seclabel.c @@ -0,0 +1,63 @@ +/* + * dummy_seclabel.c + * + * Dummy security label provider. + * + * This module does not provide anything worthwhile from a security + * perspective, but allows regression testing independent of platform-specific + * features like SELinux. + * + * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + */ +#include "postgres.h" + +#include "commands/seclabel.h" +#include "fmgr.h" +#include "miscadmin.h" +#include "utils/rel.h" + +PG_MODULE_MAGIC; + +/* Entrypoint of the module */ +void _PG_init(void); + +PG_FUNCTION_INFO_V1(dummy_seclabel_dummy); + +static void +dummy_object_relabel(const ObjectAddress *object, const char *seclabel) +{ + if (seclabel == NULL || + strcmp(seclabel, "unclassified") == 0 || + strcmp(seclabel, "classified") == 0) + return; + + if (strcmp(seclabel, "secret") == 0 || + strcmp(seclabel, "top secret") == 0) + { + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("only superuser can set '%s' label", seclabel))); + return; + } + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("'%s' is not a valid security label", seclabel))); +} + +void +_PG_init(void) +{ + register_label_provider("dummy", dummy_object_relabel); +} + +/* + * This function is here just so that the extension is not completely empty + * and the dynamic library is loaded when CREATE EXTENSION runs. + */ +Datum +dummy_seclabel_dummy(PG_FUNCTION_ARGS) +{ + PG_RETURN_VOID(); +} diff --git a/src/test/modules/dummy_seclabel/dummy_seclabel.control b/src/test/modules/dummy_seclabel/dummy_seclabel.control new file mode 100644 index 0000000..8c37272 --- /dev/null +++ b/src/test/modules/dummy_seclabel/dummy_seclabel.control @@ -0,0 +1,4 @@ +comment = 'Test code for SECURITY LABEL feature' +default_version = '1.0' +module_pathname = '$libdir/dummy_seclabel' +relocatable = true diff --git a/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out new file mode 100644 index 0000000..b2d898a --- /dev/null +++ b/src/test/modules/dummy_seclabel/expected/dummy_seclabel.out @@ -0,0 +1,117 @@ +-- +-- Test for facilities of security label +-- +CREATE EXTENSION dummy_seclabel; +-- initial setups +SET client_min_messages TO 'warning'; +DROP ROLE IF EXISTS regress_dummy_seclabel_user1; +DROP ROLE IF EXISTS regress_dummy_seclabel_user2; +RESET client_min_messages; +CREATE USER regress_dummy_seclabel_user1 WITH CREATEROLE; +CREATE USER regress_dummy_seclabel_user2; +CREATE TABLE dummy_seclabel_tbl1 (a int, b text); +CREATE TABLE dummy_seclabel_tbl2 (x int, y text); +CREATE VIEW dummy_seclabel_view1 AS SELECT * FROM dummy_seclabel_tbl2; +CREATE FUNCTION dummy_seclabel_four() RETURNS integer AS $$SELECT 4$$ language sql; +CREATE DOMAIN dummy_seclabel_domain AS text; +ALTER TABLE dummy_seclabel_tbl1 OWNER TO regress_dummy_seclabel_user1; +ALTER TABLE dummy_seclabel_tbl2 OWNER TO regress_dummy_seclabel_user2; +-- +-- Test of SECURITY LABEL statement with a plugin +-- +SET SESSION AUTHORIZATION regress_dummy_seclabel_user1; +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'classified'; -- OK +SECURITY LABEL ON COLUMN dummy_seclabel_tbl1.a IS 'unclassified'; -- OK +SECURITY LABEL ON COLUMN dummy_seclabel_tbl1 IS 'unclassified'; -- fail +ERROR: column name must be qualified +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS '...invalid label...'; -- fail +ERROR: '...invalid label...' is not a valid security label +SECURITY LABEL FOR 'dummy' ON TABLE dummy_seclabel_tbl1 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON TABLE dummy_seclabel_tbl1 IS 'classified'; -- fail +ERROR: security label provider "unknown_seclabel" is not loaded +SECURITY LABEL ON TABLE dummy_seclabel_tbl2 IS 'unclassified'; -- fail (not owner) +ERROR: must be owner of table dummy_seclabel_tbl2 +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'secret'; -- fail (not superuser) +ERROR: only superuser can set 'secret' label +SECURITY LABEL ON TABLE dummy_seclabel_tbl3 IS 'unclassified'; -- fail (not found) +ERROR: relation "dummy_seclabel_tbl3" does not exist +SET SESSION AUTHORIZATION regress_dummy_seclabel_user2; +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'unclassified'; -- fail +ERROR: must be owner of table dummy_seclabel_tbl1 +SECURITY LABEL ON TABLE dummy_seclabel_tbl2 IS 'classified'; -- OK +-- +-- Test for shared database object +-- +SET SESSION AUTHORIZATION regress_dummy_seclabel_user1; +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS 'classified'; -- OK +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS '...invalid label...'; -- fail +ERROR: '...invalid label...' is not a valid security label +SECURITY LABEL FOR 'dummy' ON ROLE regress_dummy_seclabel_user2 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON ROLE regress_dummy_seclabel_user1 IS 'unclassified'; -- fail +ERROR: security label provider "unknown_seclabel" is not loaded +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS 'secret'; -- fail (not superuser) +ERROR: only superuser can set 'secret' label +SECURITY LABEL ON ROLE regress_dummy_seclabel_user3 IS 'unclassified'; -- fail (not found) +ERROR: role "regress_dummy_seclabel_user3" does not exist +SET SESSION AUTHORIZATION regress_dummy_seclabel_user2; +SECURITY LABEL ON ROLE regress_dummy_seclabel_user2 IS 'unclassified'; -- fail (not privileged) +ERROR: must have CREATEROLE privilege +RESET SESSION AUTHORIZATION; +-- +-- Test for various types of object +-- +RESET SESSION AUTHORIZATION; +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'top secret'; -- OK +SECURITY LABEL ON VIEW dummy_seclabel_view1 IS 'classified'; -- OK +SECURITY LABEL ON FUNCTION dummy_seclabel_four() IS 'classified'; -- OK +SECURITY LABEL ON DOMAIN dummy_seclabel_domain IS 'classified'; -- OK +CREATE SCHEMA dummy_seclabel_test; +SECURITY LABEL ON SCHEMA dummy_seclabel_test IS 'unclassified'; -- OK +SET client_min_messages = error; +CREATE PUBLICATION dummy_pub; +CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (connect = false, slot_name = NONE); +RESET client_min_messages; +SECURITY LABEL ON PUBLICATION dummy_pub IS 'classified'; +SECURITY LABEL ON SUBSCRIPTION dummy_sub IS 'classified'; +SELECT objtype, objname, provider, label FROM pg_seclabels + ORDER BY objtype, objname; + objtype | objname | provider | label +--------------+------------------------------+----------+-------------- + column | dummy_seclabel_tbl1.a | dummy | unclassified + domain | dummy_seclabel_domain | dummy | classified + function | dummy_seclabel_four() | dummy | classified + publication | dummy_pub | dummy | classified + role | regress_dummy_seclabel_user1 | dummy | classified + role | regress_dummy_seclabel_user2 | dummy | unclassified + schema | dummy_seclabel_test | dummy | unclassified + subscription | dummy_sub | dummy | classified + table | dummy_seclabel_tbl1 | dummy | top secret + table | dummy_seclabel_tbl2 | dummy | classified + view | dummy_seclabel_view1 | dummy | classified +(11 rows) + +-- check for event trigger +CREATE FUNCTION event_trigger_test() +RETURNS event_trigger AS $$ + BEGIN RAISE NOTICE 'event %: %', TG_EVENT, TG_TAG; END; +$$ LANGUAGE plpgsql; +CREATE EVENT TRIGGER always_start ON ddl_command_start +EXECUTE PROCEDURE event_trigger_test(); +CREATE EVENT TRIGGER always_end ON ddl_command_end +EXECUTE PROCEDURE event_trigger_test(); +CREATE EVENT TRIGGER always_drop ON sql_drop +EXECUTE PROCEDURE event_trigger_test(); +CREATE EVENT TRIGGER always_rewrite ON table_rewrite +EXECUTE PROCEDURE event_trigger_test(); +-- should trigger ddl_command_{start,end} +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'classified'; +NOTICE: event ddl_command_start: SECURITY LABEL +NOTICE: event ddl_command_end: SECURITY LABEL +-- clean up +DROP EVENT TRIGGER always_start, always_end, always_drop, always_rewrite; +DROP VIEW dummy_seclabel_view1; +DROP TABLE dummy_seclabel_tbl1, dummy_seclabel_tbl2; +DROP SUBSCRIPTION dummy_sub; +DROP PUBLICATION dummy_pub; +DROP ROLE regress_dummy_seclabel_user1; +DROP ROLE regress_dummy_seclabel_user2; diff --git a/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql b/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql new file mode 100644 index 0000000..8c347b6 --- /dev/null +++ b/src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql @@ -0,0 +1,115 @@ +-- +-- Test for facilities of security label +-- +CREATE EXTENSION dummy_seclabel; + +-- initial setups +SET client_min_messages TO 'warning'; + +DROP ROLE IF EXISTS regress_dummy_seclabel_user1; +DROP ROLE IF EXISTS regress_dummy_seclabel_user2; + +RESET client_min_messages; + +CREATE USER regress_dummy_seclabel_user1 WITH CREATEROLE; +CREATE USER regress_dummy_seclabel_user2; + +CREATE TABLE dummy_seclabel_tbl1 (a int, b text); +CREATE TABLE dummy_seclabel_tbl2 (x int, y text); +CREATE VIEW dummy_seclabel_view1 AS SELECT * FROM dummy_seclabel_tbl2; +CREATE FUNCTION dummy_seclabel_four() RETURNS integer AS $$SELECT 4$$ language sql; +CREATE DOMAIN dummy_seclabel_domain AS text; + +ALTER TABLE dummy_seclabel_tbl1 OWNER TO regress_dummy_seclabel_user1; +ALTER TABLE dummy_seclabel_tbl2 OWNER TO regress_dummy_seclabel_user2; + +-- +-- Test of SECURITY LABEL statement with a plugin +-- +SET SESSION AUTHORIZATION regress_dummy_seclabel_user1; + +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'classified'; -- OK +SECURITY LABEL ON COLUMN dummy_seclabel_tbl1.a IS 'unclassified'; -- OK +SECURITY LABEL ON COLUMN dummy_seclabel_tbl1 IS 'unclassified'; -- fail +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS '...invalid label...'; -- fail +SECURITY LABEL FOR 'dummy' ON TABLE dummy_seclabel_tbl1 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON TABLE dummy_seclabel_tbl1 IS 'classified'; -- fail +SECURITY LABEL ON TABLE dummy_seclabel_tbl2 IS 'unclassified'; -- fail (not owner) +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'secret'; -- fail (not superuser) +SECURITY LABEL ON TABLE dummy_seclabel_tbl3 IS 'unclassified'; -- fail (not found) + +SET SESSION AUTHORIZATION regress_dummy_seclabel_user2; +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'unclassified'; -- fail +SECURITY LABEL ON TABLE dummy_seclabel_tbl2 IS 'classified'; -- OK + +-- +-- Test for shared database object +-- +SET SESSION AUTHORIZATION regress_dummy_seclabel_user1; + +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS 'classified'; -- OK +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS '...invalid label...'; -- fail +SECURITY LABEL FOR 'dummy' ON ROLE regress_dummy_seclabel_user2 IS 'unclassified'; -- OK +SECURITY LABEL FOR 'unknown_seclabel' ON ROLE regress_dummy_seclabel_user1 IS 'unclassified'; -- fail +SECURITY LABEL ON ROLE regress_dummy_seclabel_user1 IS 'secret'; -- fail (not superuser) +SECURITY LABEL ON ROLE regress_dummy_seclabel_user3 IS 'unclassified'; -- fail (not found) + +SET SESSION AUTHORIZATION regress_dummy_seclabel_user2; +SECURITY LABEL ON ROLE regress_dummy_seclabel_user2 IS 'unclassified'; -- fail (not privileged) + +RESET SESSION AUTHORIZATION; + +-- +-- Test for various types of object +-- +RESET SESSION AUTHORIZATION; + +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'top secret'; -- OK +SECURITY LABEL ON VIEW dummy_seclabel_view1 IS 'classified'; -- OK +SECURITY LABEL ON FUNCTION dummy_seclabel_four() IS 'classified'; -- OK +SECURITY LABEL ON DOMAIN dummy_seclabel_domain IS 'classified'; -- OK +CREATE SCHEMA dummy_seclabel_test; +SECURITY LABEL ON SCHEMA dummy_seclabel_test IS 'unclassified'; -- OK + +SET client_min_messages = error; +CREATE PUBLICATION dummy_pub; +CREATE SUBSCRIPTION dummy_sub CONNECTION '' PUBLICATION foo WITH (connect = false, slot_name = NONE); +RESET client_min_messages; +SECURITY LABEL ON PUBLICATION dummy_pub IS 'classified'; +SECURITY LABEL ON SUBSCRIPTION dummy_sub IS 'classified'; + +SELECT objtype, objname, provider, label FROM pg_seclabels + ORDER BY objtype, objname; + +-- check for event trigger +CREATE FUNCTION event_trigger_test() +RETURNS event_trigger AS $$ + BEGIN RAISE NOTICE 'event %: %', TG_EVENT, TG_TAG; END; +$$ LANGUAGE plpgsql; + +CREATE EVENT TRIGGER always_start ON ddl_command_start +EXECUTE PROCEDURE event_trigger_test(); + +CREATE EVENT TRIGGER always_end ON ddl_command_end +EXECUTE PROCEDURE event_trigger_test(); + +CREATE EVENT TRIGGER always_drop ON sql_drop +EXECUTE PROCEDURE event_trigger_test(); + +CREATE EVENT TRIGGER always_rewrite ON table_rewrite +EXECUTE PROCEDURE event_trigger_test(); + +-- should trigger ddl_command_{start,end} +SECURITY LABEL ON TABLE dummy_seclabel_tbl1 IS 'classified'; + +-- clean up +DROP EVENT TRIGGER always_start, always_end, always_drop, always_rewrite; + +DROP VIEW dummy_seclabel_view1; +DROP TABLE dummy_seclabel_tbl1, dummy_seclabel_tbl2; + +DROP SUBSCRIPTION dummy_sub; +DROP PUBLICATION dummy_pub; + +DROP ROLE regress_dummy_seclabel_user1; +DROP ROLE regress_dummy_seclabel_user2; |