mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-16 02:23:49 +08:00
Fixes permission handling
Previously, catalog tables were not fully protected from malicious non-superusers. This PR fixes permission handling be severely restricting permissions to the catalog and instead using SECURITY DEFINER functions to alter the catalog when needed without giving users permission to do those same operations outside of these functions. In addition, these functions check for proper permissions themselves so are safe to use. This PR also makes sure that chunk tables have the same owner as the hypertable and correctly handles `ALTER TABLE...OWNER TO` commands to keep this info in sync.
This commit is contained in:
parent
aca7f326b3
commit
97681c2328
1
Makefile
1
Makefile
@ -29,6 +29,7 @@ SRCS = \
|
||||
src/hypertable.c \
|
||||
src/dimension.c \
|
||||
src/dimension_slice.c \
|
||||
src/ddl_utils.c \
|
||||
src/chunk_constraint.c \
|
||||
src/partitioning.c \
|
||||
src/insert.c \
|
||||
|
@ -270,7 +270,9 @@ CREATE OR REPLACE FUNCTION _timescaledb_internal.chunk_create(
|
||||
dimension_ids INTEGER[],
|
||||
dimension_values BIGINT[]
|
||||
)
|
||||
RETURNS _timescaledb_catalog.chunk LANGUAGE PLPGSQL VOLATILE AS
|
||||
RETURNS _timescaledb_catalog.chunk LANGUAGE PLPGSQL VOLATILE
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
chunk_row _timescaledb_catalog.chunk;
|
||||
|
@ -21,12 +21,15 @@ CREATE OR REPLACE FUNCTION create_hypertable(
|
||||
create_default_indexes BOOLEAN = TRUE,
|
||||
if_not_exists BOOLEAN = FALSE
|
||||
)
|
||||
RETURNS VOID LANGUAGE PLPGSQL VOLATILE AS
|
||||
RETURNS VOID LANGUAGE PLPGSQL VOLATILE
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
hypertable_row _timescaledb_catalog.hypertable;
|
||||
table_name NAME;
|
||||
schema_name NAME;
|
||||
table_owner NAME;
|
||||
tablespace_oid OID;
|
||||
tablespace_name NAME;
|
||||
time_column_type REGTYPE;
|
||||
@ -41,6 +44,17 @@ BEGIN
|
||||
INNER JOIN pg_namespace n ON (n.OID = c.relnamespace)
|
||||
WHERE c.OID = main_table;
|
||||
|
||||
SELECT tableowner
|
||||
INTO STRICT table_owner
|
||||
FROM pg_catalog.pg_tables
|
||||
WHERE schemaname = schema_name
|
||||
AND tablename = table_name;
|
||||
|
||||
IF table_owner <> session_user THEN
|
||||
RAISE 'Must be owner of relation %', table_name
|
||||
USING ERRCODE = 'insufficient_privilege';
|
||||
END IF;
|
||||
|
||||
-- tables that don't have an associated tablespace has reltablespace OID set to 0
|
||||
-- in pg_class and there is no matching row in pg_tablespace
|
||||
SELECT spcname
|
||||
|
@ -9,9 +9,19 @@
|
||||
|
||||
*/
|
||||
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_is_change_owner(pg_ddl_command)
|
||||
RETURNS bool IMMUTABLE STRICT
|
||||
AS '$libdir/timescaledb' LANGUAGE C;
|
||||
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_change_owner_to(pg_ddl_command)
|
||||
RETURNS name IMMUTABLE STRICT
|
||||
AS '$libdir/timescaledb' LANGUAGE C;
|
||||
|
||||
-- Handles ddl create index commands on hypertables
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_process_create_index()
|
||||
RETURNS event_trigger LANGUAGE plpgsql AS
|
||||
RETURNS event_trigger LANGUAGE plpgsql
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
info record;
|
||||
@ -19,6 +29,7 @@ DECLARE
|
||||
def TEXT;
|
||||
hypertable_row _timescaledb_catalog.hypertable;
|
||||
BEGIN
|
||||
--NOTE: pg_event_trigger_ddl_commands prevents this SECURITY DEFINER function from being called outside trigger.
|
||||
FOR info IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||
LOOP
|
||||
-- get table oid
|
||||
@ -72,12 +83,15 @@ $BODY$;
|
||||
|
||||
-- Handles ddl alter index commands on hypertables
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_process_alter_index()
|
||||
RETURNS event_trigger LANGUAGE plpgsql AS
|
||||
RETURNS event_trigger LANGUAGE plpgsql
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
info record;
|
||||
table_oid regclass;
|
||||
BEGIN
|
||||
--NOTE: pg_event_trigger_ddl_commands prevents this SECURITY DEFINER function from being called outside trigger.
|
||||
FOR info IN SELECT * FROM pg_event_trigger_ddl_commands()
|
||||
LOOP
|
||||
SELECT indrelid INTO STRICT table_oid
|
||||
@ -96,13 +110,16 @@ $BODY$;
|
||||
|
||||
-- Handles ddl drop index commands on hypertables
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_process_drop_index()
|
||||
RETURNS event_trigger LANGUAGE plpgsql AS
|
||||
RETURNS event_trigger LANGUAGE plpgsql
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
info record;
|
||||
table_oid regclass;
|
||||
hypertable_row _timescaledb_catalog.hypertable;
|
||||
BEGIN
|
||||
--NOTE: pg_event_trigger_ddl_commands prevents this SECURITY DEFINER function from being called outside trigger.
|
||||
FOR info IN SELECT * FROM pg_event_trigger_dropped_objects()
|
||||
LOOP
|
||||
SELECT format('%I.%I', h.schema_name, h.table_name) INTO table_oid
|
||||
@ -135,3 +152,43 @@ BEGIN
|
||||
END LOOP;
|
||||
END
|
||||
$BODY$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION _timescaledb_internal.ddl_process_alter_table()
|
||||
RETURNS event_trigger LANGUAGE plpgsql
|
||||
SECURITY DEFINER SET search_path = ''
|
||||
AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
info record;
|
||||
new_table_owner TEXT;
|
||||
chunk_row _timescaledb_catalog.chunk;
|
||||
hypertable_row _timescaledb_catalog.hypertable;
|
||||
BEGIN
|
||||
--NOTE: pg_event_trigger_ddl_commands prevents this SECURITY DEFINER function from being called outside trigger.
|
||||
FOR info IN SELECT * FROM pg_event_trigger_ddl_commands() LOOP
|
||||
IF NOT _timescaledb_internal.is_main_table(info.objid) THEN
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
IF _timescaledb_internal.ddl_is_change_owner(info.command) THEN
|
||||
--if change owner then change owners on all chunks
|
||||
new_table_owner := _timescaledb_internal.ddl_change_owner_to(info.command);
|
||||
hypertable_row := _timescaledb_internal.hypertable_from_main_table(info.objid);
|
||||
|
||||
FOR chunk_row IN
|
||||
SELECT *
|
||||
FROM _timescaledb_catalog.chunk
|
||||
WHERE hypertable_id = hypertable_row.id
|
||||
LOOP
|
||||
EXECUTE format(
|
||||
$$
|
||||
ALTER TABLE %1$I.%2$I OWNER TO %3$I
|
||||
$$,
|
||||
chunk_row.schema_name, chunk_row.table_name,
|
||||
new_table_owner
|
||||
);
|
||||
END LOOP;
|
||||
END IF;
|
||||
END LOOP;
|
||||
END
|
||||
$BODY$;
|
||||
|
@ -1,32 +1,11 @@
|
||||
-- This sets up the permissions for entities created by this extension.
|
||||
|
||||
-- schema permisions
|
||||
GRANT USAGE ON SCHEMA _timescaledb_catalog, _timescaledb_internal, _timescaledb_cache
|
||||
TO PUBLIC;
|
||||
|
||||
GRANT USAGE, CREATE ON SCHEMA _timescaledb_internal TO PUBLIC;
|
||||
GRANT USAGE ON SCHEMA _timescaledb_catalog, _timescaledb_internal TO PUBLIC;
|
||||
|
||||
-- needed for working with hypertables
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA _timescaledb_catalog TO PUBLIC;
|
||||
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA _timescaledb_catalog TO PUBLIC;
|
||||
|
||||
-- Needed but dangerous. Anybody can mess up the _timescaledb_catalog.
|
||||
-- MUST DOCUMENT TODO: remove these permissions. Have c-based workaround.
|
||||
-- Everything below this line is suspect.
|
||||
GRANT INSERT ON TABLE
|
||||
_timescaledb_catalog.hypertable, _timescaledb_catalog.chunk,
|
||||
_timescaledb_catalog.dimension, _timescaledb_catalog.dimension_slice, _timescaledb_catalog.chunk_constraint
|
||||
TO PUBLIC;
|
||||
|
||||
-- needed for inserts to hypertable
|
||||
GRANT UPDATE ON TABLE _timescaledb_catalog.hypertable, _timescaledb_catalog.chunk -- needed for lock
|
||||
TO PUBLIC;
|
||||
|
||||
-- needed for ddl
|
||||
GRANT INSERT, DELETE ON TABLE _timescaledb_catalog.hypertable_index, _timescaledb_catalog.chunk_index
|
||||
TO PUBLIC;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -62,6 +62,10 @@ BEGIN
|
||||
WHEN tag IN ('create trigger')
|
||||
EXECUTE PROCEDURE _timescaledb_internal.ddl_process_create_trigger();
|
||||
|
||||
CREATE EVENT TRIGGER ddl_alter_table ON ddl_command_end
|
||||
WHEN tag IN ('alter table')
|
||||
EXECUTE PROCEDURE _timescaledb_internal.ddl_process_alter_table();
|
||||
|
||||
CREATE EVENT TRIGGER ddl_check_drop_command
|
||||
ON sql_drop
|
||||
EXECUTE PROCEDURE _timescaledb_internal.ddl_process_drop_table();
|
||||
@ -71,6 +75,7 @@ BEGIN
|
||||
ALTER EXTENSION timescaledb ADD EVENT TRIGGER ddl_alter_index;
|
||||
ALTER EXTENSION timescaledb ADD EVENT TRIGGER ddl_drop_index;
|
||||
ALTER EXTENSION timescaledb ADD EVENT TRIGGER ddl_create_trigger;
|
||||
ALTER EXTENSION timescaledb ADD EVENT TRIGGER ddl_alter_table;
|
||||
ALTER EXTENSION timescaledb ADD EVENT TRIGGER ddl_check_drop_command;
|
||||
END IF;
|
||||
|
||||
|
@ -27,6 +27,7 @@ DECLARE
|
||||
hypertable_row _timescaledb_catalog.hypertable;
|
||||
tablespace_clause TEXT := '';
|
||||
tablespace_name NAME;
|
||||
table_owner NAME;
|
||||
tablespace_oid OID;
|
||||
BEGIN
|
||||
SELECT * INTO STRICT chunk_row
|
||||
@ -44,6 +45,12 @@ BEGIN
|
||||
FROM pg_catalog.pg_tablespace t
|
||||
WHERE t.spcname = tablespace_name;
|
||||
|
||||
SELECT tableowner
|
||||
INTO STRICT table_owner
|
||||
FROM pg_catalog.pg_tables
|
||||
WHERE schemaname = hypertable_row.schema_name
|
||||
AND tablename = hypertable_row.table_name;
|
||||
|
||||
IF tablespace_oid IS NOT NULL THEN
|
||||
tablespace_clause := format('TABLESPACE %s', tablespace_name);
|
||||
ELSIF tablespace_name IS NOT NULL THEN
|
||||
@ -59,6 +66,14 @@ BEGIN
|
||||
hypertable_row.schema_name, hypertable_row.table_name, tablespace_clause
|
||||
);
|
||||
|
||||
EXECUTE format(
|
||||
$$
|
||||
ALTER TABLE %1$I.%2$I OWNER TO %3$I
|
||||
$$,
|
||||
chunk_row.schema_name, chunk_row.table_name,
|
||||
table_owner
|
||||
);
|
||||
|
||||
PERFORM _timescaledb_internal.chunk_add_constraints(chunk_id);
|
||||
END
|
||||
$BODY$;
|
||||
|
71
src/ddl_utils.c
Normal file
71
src/ddl_utils.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <postgres.h>
|
||||
#include <tcop/deparse_utility.h>
|
||||
|
||||
#include "ddl_utils.h"
|
||||
|
||||
enum ddl_cmd_type
|
||||
{
|
||||
DDL_CHANGE_OWNER, DDL_OTHER
|
||||
};
|
||||
|
||||
static enum ddl_cmd_type
|
||||
ddl_alter_table_subcmd(CollectedCommand *cmd)
|
||||
{
|
||||
ListCell *cell;
|
||||
|
||||
if (cmd->type == SCT_AlterTable)
|
||||
{
|
||||
foreach(cell, cmd->d.alterTable.subcmds)
|
||||
{
|
||||
CollectedATSubcmd *sub = lfirst(cell);
|
||||
AlterTableCmd *subcmd = (AlterTableCmd *) sub->parsetree;
|
||||
|
||||
Assert(IsA(subcmd, AlterTableCmd));
|
||||
|
||||
switch (subcmd->subtype)
|
||||
{
|
||||
case AT_ChangeOwner:
|
||||
return DDL_CHANGE_OWNER;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DDL_OTHER;
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
ddl_change_owner_to(PG_FUNCTION_ARGS)
|
||||
{
|
||||
CollectedATSubcmd *sub;
|
||||
AlterTableCmd *altersub;
|
||||
RoleSpec *role;
|
||||
Name user = palloc0(NAMEDATALEN);
|
||||
CollectedCommand *cmd = (CollectedCommand *) PG_GETARG_POINTER(0);
|
||||
|
||||
Assert(cmd->type == SCT_AlterTable);
|
||||
Assert(list_length(cmd->d.alterTable.subcmds) == 1);
|
||||
sub = linitial(cmd->d.alterTable.subcmds);
|
||||
|
||||
Assert(IsA(sub->parsetree, AlterTableCmd));
|
||||
altersub = (AlterTableCmd *) sub->parsetree;
|
||||
|
||||
Assert(IsA(altersub->newowner, RoleSpec));
|
||||
role = (RoleSpec *) altersub->newowner;
|
||||
|
||||
memcpy(user->data, role->rolename, NAMEDATALEN);
|
||||
|
||||
PG_RETURN_NAME(user);
|
||||
}
|
||||
|
||||
Datum
|
||||
ddl_is_change_owner(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool ret =
|
||||
DDL_CHANGE_OWNER == ddl_alter_table_subcmd(
|
||||
(CollectedCommand *) PG_GETARG_POINTER(0)
|
||||
);
|
||||
|
||||
PG_RETURN_BOOL(ret);
|
||||
}
|
9
src/ddl_utils.h
Normal file
9
src/ddl_utils.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef TIMESCALEDB_DDL_UTILS_H
|
||||
#define TIMESCALEDB_DDL_UTILS_H
|
||||
#include <postgres.h>
|
||||
#include <fmgr.h>
|
||||
|
||||
PG_FUNCTION_INFO_V1(ddl_is_change_owner);
|
||||
PG_FUNCTION_INFO_V1(ddl_change_owner_to);
|
||||
|
||||
#endif /* TIMESCALEDB_DDL_UTILS_H */
|
@ -97,14 +97,14 @@ insert_chunk_state_new(Chunk *chunk)
|
||||
|
||||
rel = heap_open(chunk->table_id, RowExclusiveLock);
|
||||
|
||||
/* permission check */
|
||||
rte = makeNode(RangeTblEntry);
|
||||
rte->rtekind = RTE_RELATION;
|
||||
rte->relid = RelationGetRelid(rel);
|
||||
rte->relkind = rel->rd_rel->relkind;
|
||||
rte->requiredPerms = ACL_INSERT;
|
||||
range_table = list_make1(rte);
|
||||
ExecCheckRTPerms(range_table, true);
|
||||
|
||||
/* permissions NOT checked here; were checked at hypertable level */
|
||||
|
||||
if (check_enable_rls(rte->relid, InvalidOid, false) == RLS_ENABLED)
|
||||
ereport(ERROR,
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <postgres.h>
|
||||
#include <utils/lsyscache.h>
|
||||
#include <catalog/pg_class.h>
|
||||
|
||||
#include "insert_statement_state.h"
|
||||
#include "insert_chunk_state.h"
|
||||
@ -21,6 +22,7 @@ insert_statement_state_new(Oid relid)
|
||||
InsertStatementState *state;
|
||||
Hypertable *ht;
|
||||
Cache *hypertable_cache;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
oldctx = MemoryContextSwitchTo(mctx);
|
||||
|
||||
@ -37,6 +39,14 @@ insert_statement_state_new(Oid relid)
|
||||
state->hypertable = ht;
|
||||
state->cache = subspace_store_init(HYPERSPACE_NUM_DIMENSIONS(ht->space), mctx);
|
||||
|
||||
/* permission check: check hypertable permissions */
|
||||
rte = makeNode(RangeTblEntry);
|
||||
rte->rtekind = RTE_RELATION;
|
||||
rte->relid = relid;
|
||||
rte->relkind = RELKIND_RELATION;
|
||||
rte->requiredPerms = ACL_INSERT;
|
||||
ExecCheckRTPerms(list_make1(rte), true);
|
||||
|
||||
MemoryContextSwitchTo(oldctx);
|
||||
|
||||
return state;
|
||||
|
@ -51,7 +51,9 @@ EXCEPTION
|
||||
WHEN duplicate_object THEN
|
||||
--mute error
|
||||
END$$;
|
||||
--needed for ddl ops:
|
||||
CREATE SCHEMA IF NOT EXISTS "customSchema" AUTHORIZATION alt_usr;
|
||||
--test creating and using schema as non-superuser
|
||||
\c single alt_usr
|
||||
\dt
|
||||
List of relations
|
||||
@ -445,7 +447,7 @@ $BODY$;
|
||||
\set ON_ERROR_STOP 0
|
||||
ALTER TABLE PUBLIC."Hypertable_1" ALTER COLUMN sensor_2_renamed SET DATA TYPE int;
|
||||
ALTER INDEX "ind_humidity" RENAME TO "ind_humdity2";
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable "Hypertable_1"
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable public."Hypertable_1"
|
||||
CREATE TRIGGER test_trigger BEFORE UPDATE OR DELETE ON PUBLIC."Hypertable_1"
|
||||
FOR EACH STATEMENT EXECUTE PROCEDURE empty_trigger_func();
|
||||
psql:include/ddl_ops_2.sql:26: ERROR: CREATE TRIGGER not supported on hypertable "Hypertable_1"
|
||||
@ -455,3 +457,91 @@ ALTER TABLE PUBLIC."Hypertable_1" ADD COLUMN sensor_3 BIGINT NOT NULL DEFAULT 13
|
||||
--create column with same name as previously dropped one
|
||||
ALTER TABLE PUBLIC."Hypertable_1" ADD COLUMN sensor_4 BIGINT NOT NULL DEFAULT 131;
|
||||
|
||||
--test proper denials for all security definer functions:
|
||||
\c single postgres
|
||||
CREATE TABLE plain_table_su (time timestamp, temp float);
|
||||
CREATE TABLE hypertable_su (time timestamp, temp float);
|
||||
SELECT create_hypertable('hypertable_su', 'time');
|
||||
create_hypertable
|
||||
-------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
CREATE INDEX "ind_1" ON hypertable_su (time);
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
\c single alt_usr
|
||||
--all of the following should produce errors
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT create_hypertable('plain_table_su', 'time');
|
||||
ERROR: Must be owner of relation plain_table_su
|
||||
CREATE INDEX ON plain_table_su (time, temp);
|
||||
ERROR: must be owner of relation plain_table_su
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
DROP INDEX "ind_1";
|
||||
ERROR: must be owner of relation ind_1
|
||||
ALTER INDEX "ind_1" RENAME TO "ind_2";
|
||||
ERROR: must be owner of relation ind_1
|
||||
\set ON_ERROR_STOP 1
|
||||
--test that I can't do anything to a non-owned hypertable.
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
SELECT * FROM hypertable_su;
|
||||
ERROR: permission denied for relation hypertable_su
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
ERROR: permission denied for relation hypertable_su
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
\set ON_ERROR_STOP 1
|
||||
--grant read permissions
|
||||
\c single postgres
|
||||
GRANT SELECT ON hypertable_su TO alt_usr;
|
||||
\c single alt_usr
|
||||
SELECT * FROM hypertable_su;
|
||||
time | temp
|
||||
--------------------------+------
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
(1 row)
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
ERROR: permission denied for relation hypertable_su
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
\set ON_ERROR_STOP 1
|
||||
--grant read, insert permissions
|
||||
\c single postgres
|
||||
GRANT SELECT, INSERT ON hypertable_su TO alt_usr;
|
||||
\c single alt_usr
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
SELECT * FROM hypertable_su;
|
||||
time | temp
|
||||
--------------------------+------
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
(2 rows)
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
ERROR: must be owner of relation hypertable_su
|
||||
\set ON_ERROR_STOP 1
|
||||
--change owner
|
||||
\c single postgres
|
||||
ALTER TABLE hypertable_su OWNER TO alt_usr;
|
||||
\c single alt_usr
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
SELECT * FROM hypertable_su;
|
||||
time | temp
|
||||
--------------------------+------
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
Fri Jan 20 09:00:01 2017 | 22.5
|
||||
(3 rows)
|
||||
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
|
@ -428,7 +428,7 @@ $BODY$;
|
||||
\set ON_ERROR_STOP 0
|
||||
ALTER TABLE PUBLIC."Hypertable_1" ALTER COLUMN sensor_2_renamed SET DATA TYPE int;
|
||||
ALTER INDEX "ind_humidity" RENAME TO "ind_humdity2";
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable "Hypertable_1"
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable public."Hypertable_1"
|
||||
CREATE TRIGGER test_trigger BEFORE UPDATE OR DELETE ON PUBLIC."Hypertable_1"
|
||||
FOR EACH STATEMENT EXECUTE PROCEDURE empty_trigger_func();
|
||||
psql:include/ddl_ops_2.sql:26: ERROR: CREATE TRIGGER not supported on hypertable "Hypertable_1"
|
||||
|
@ -36,4 +36,4 @@ SELECT * FROM create_hypertable('"public"."Hypertable_1"', 'time', 'Device_id',
|
||||
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT * FROM create_hypertable('"public"."Hypertable_1"', 'time', 'Device_id', 2);
|
||||
ERROR: hypertable "Hypertable_1" already exists
|
||||
ERROR: hypertable public."Hypertable_1" already exists
|
||||
|
@ -367,7 +367,7 @@ $BODY$;
|
||||
\set ON_ERROR_STOP 0
|
||||
ALTER TABLE PUBLIC."Hypertable_1" ALTER COLUMN sensor_2_renamed SET DATA TYPE int;
|
||||
ALTER INDEX "ind_humidity" RENAME TO "ind_humdity2";
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable "Hypertable_1"
|
||||
psql:include/ddl_ops_2.sql:24: ERROR: ALTER INDEX not supported on hypertable public."Hypertable_1"
|
||||
CREATE TRIGGER test_trigger BEFORE UPDATE OR DELETE ON PUBLIC."Hypertable_1"
|
||||
FOR EACH STATEMENT EXECUTE PROCEDURE empty_trigger_func();
|
||||
psql:include/ddl_ops_2.sql:26: ERROR: CREATE TRIGGER not supported on hypertable "Hypertable_1"
|
||||
|
@ -25,7 +25,7 @@ SELECT create_hypertable('should_drop', 'time');
|
||||
-- Calling create hypertable again will increment hypertable ID
|
||||
-- although no new hypertable is created. Make sure we can handle this.
|
||||
SELECT create_hypertable('should_drop', 'time', if_not_exists => true);
|
||||
NOTICE: hypertable should_drop already exists, skipping
|
||||
NOTICE: hypertable public.should_drop already exists, skipping
|
||||
create_hypertable
|
||||
-------------------
|
||||
|
||||
|
@ -42,7 +42,7 @@ SELECT count(*)
|
||||
AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb');
|
||||
count
|
||||
-------
|
||||
104
|
||||
108
|
||||
(1 row)
|
||||
|
||||
\c postgres
|
||||
@ -66,7 +66,7 @@ SELECT count(*)
|
||||
AND refobjid = (SELECT oid FROM pg_extension WHERE extname = 'timescaledb');
|
||||
count
|
||||
-------
|
||||
104
|
||||
108
|
||||
(1 row)
|
||||
|
||||
\c single
|
||||
|
@ -8,8 +8,10 @@ EXCEPTION
|
||||
--mute error
|
||||
END$$;
|
||||
|
||||
--needed for ddl ops:
|
||||
CREATE SCHEMA IF NOT EXISTS "customSchema" AUTHORIZATION alt_usr;
|
||||
|
||||
--test creating and using schema as non-superuser
|
||||
\c single alt_usr
|
||||
\dt
|
||||
|
||||
@ -27,3 +29,63 @@ SELECT * FROM "1dim";
|
||||
|
||||
\ir include/ddl_ops_1.sql
|
||||
\ir include/ddl_ops_2.sql
|
||||
|
||||
--test proper denials for all security definer functions:
|
||||
\c single postgres
|
||||
CREATE TABLE plain_table_su (time timestamp, temp float);
|
||||
CREATE TABLE hypertable_su (time timestamp, temp float);
|
||||
SELECT create_hypertable('hypertable_su', 'time');
|
||||
CREATE INDEX "ind_1" ON hypertable_su (time);
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
|
||||
\c single alt_usr
|
||||
--all of the following should produce errors
|
||||
\set ON_ERROR_STOP 0
|
||||
SELECT create_hypertable('plain_table_su', 'time');
|
||||
CREATE INDEX ON plain_table_su (time, temp);
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
DROP INDEX "ind_1";
|
||||
ALTER INDEX "ind_1" RENAME TO "ind_2";
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--test that I can't do anything to a non-owned hypertable.
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
SELECT * FROM hypertable_su;
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--grant read permissions
|
||||
\c single postgres
|
||||
GRANT SELECT ON hypertable_su TO alt_usr;
|
||||
|
||||
\c single alt_usr
|
||||
SELECT * FROM hypertable_su;
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--grant read, insert permissions
|
||||
\c single postgres
|
||||
GRANT SELECT, INSERT ON hypertable_su TO alt_usr;
|
||||
|
||||
\c single alt_usr
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
SELECT * FROM hypertable_su;
|
||||
\set ON_ERROR_STOP 0
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
\set ON_ERROR_STOP 1
|
||||
|
||||
--change owner
|
||||
\c single postgres
|
||||
ALTER TABLE hypertable_su OWNER TO alt_usr;
|
||||
|
||||
\c single alt_usr
|
||||
INSERT INTO hypertable_su VALUES('2017-01-20T09:00:01', 22.5);
|
||||
SELECT * FROM hypertable_su;
|
||||
CREATE INDEX ON hypertable_su (time, temp);
|
||||
ALTER TABLE hypertable_su ADD COLUMN val2 integer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user