summaryrefslogtreecommitdiffstats
path: root/src/test/modules/dummy_seclabel
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:46:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:46:48 +0000
commit311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch)
tree0ec307299b1dada3701e42f4ca6eda57d708261e /src/test/modules/dummy_seclabel
parentInitial commit. (diff)
downloadpostgresql-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/.gitignore4
-rw-r--r--src/test/modules/dummy_seclabel/Makefile20
-rw-r--r--src/test/modules/dummy_seclabel/README41
-rw-r--r--src/test/modules/dummy_seclabel/dummy_seclabel--1.0.sql8
-rw-r--r--src/test/modules/dummy_seclabel/dummy_seclabel.c63
-rw-r--r--src/test/modules/dummy_seclabel/dummy_seclabel.control4
-rw-r--r--src/test/modules/dummy_seclabel/expected/dummy_seclabel.out117
-rw-r--r--src/test/modules/dummy_seclabel/sql/dummy_seclabel.sql115
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;