我有一个PostgreSQL 9.5数据库:
我在视图上使用安全定义器选项定义了一个INSTEAD触发器。此触发器更新表test.domain。问题是尽管这个触发器正在作为用户" system"执行,但表test.table上的参考更新由调用者用户执行。
这是一个例子,如果作为postgres执行,我希望得到"用户系统"作为错误而不是"用户postgres"
drop schema IF EXISTS test cascade;
create schema test;
create function test.modified() returns trigger as
$$
BEGIN
raise exception 'user %', ' '||current_user;
END
$$
language plpgsql;
set role system;
create function test.insert_with_system() returns trigger as
$$
DECLARE
valor text;
BEGIN
--raise exception 'user %', ' '||current_user;
update test.domain set value = ''||new.value where id = new.id;
END
$$ language plpgsql security definer;
reset role;
CREATE table test.domain(
id int primary key,
value text unique
);
create view test.domain_view as select * from test.domain;
create table test.table(
id int primary key,
domainn text
);
alter table test.table add foreign key (domainn)
references test.domain(value) on delete restrict on update cascade;
create trigger test_trigger before insert or update or delete on test.table
for each row execute procedure test.modified();
create trigger instead_ins INSTEAD OF update or delete on test.domain_view
for each row execute procedure test.insert_with_system();
insert into test.domain(id, value) values(1,'one');
alter table test.table DISABLE TRIGGER all;
insert into test.table(id, domainn) values (0,'one');
alter table test.table enable TRIGGER all;
update test.domain_view set value = 'two';
select * from test.table;
答案 0 :(得分:2)
级联更新始终在引用表的所有者的安全上下文中运行(在您的示例中为test.table
)。
请参阅ri_PerformCheck
中的src/backend/utils/adt/ri_triggers.c
:
/*
* Use the query type code to determine whether the query is run against
* the PK or FK table; we'll do the check as that table's owner
*/
if (qkey->constr_queryno <= RI_PLAN_LAST_ON_PK)
query_rel = pk_rel;
else
query_rel = fk_rel;
...
/* Switch to proper UID to perform check as */
GetUserIdAndSecContext(&save_userid, &save_sec_context);
SetUserIdAndSecContext(RelationGetForm(query_rel)->relowner,
save_sec_context | SECURITY_LOCAL_USERID_CHANGE |
SECURITY_NOFORCE_RLS);
我尝试将代码跟随其原点,并且行为似乎源于提交465cf168eb6151275016486fe2d2c629fed967ca。
搜索黑客档案以进行相关讨论,我找到了this。
因此,据我所知,该行为试图避免以下情况:
用户A
拥有atable
并在该表格上向用户REFERENCES
授予B
。
用户B
拥有btable
并使用atable
向ON UPDATE OR DELETE CASCADE
添加外键。用户A
对btable
无权限。
用户A
尝试更新或删除atable
中与btable
级联但未通过“权限被拒绝”错误的行。
我个人不确定目前的行为是否良好,但我可以看出A
'无法修改她所拥有的表格会令人感到意外。