Обновление с включенной безопасностью на уровне строк не работает, в то время как стандартное обновление использует ту же логику - PullRequest
0 голосов
/ 10 января 2019

Работа на postgres 10.4 (на RDS, если это имеет значение) Я пытаюсь обеспечить соблюдение прав пользователя приложения с помощью Row Level Security.

У меня есть таблица разрешений, которая выглядит примерно так:

user_group_id | entity1 | entity2 | entity3 | permission
==============|=========|=========|=========|============
1             |1        |null     |null     | write
1             |1        |1        |null     | read
  1. entity1 (root) -entity2-entity3 (leaf) - это иерархия элементов, хранящихся в разных таблицах. entity1 содержит элементы entity2, entity2 содержит элементы entity3.

  2. разрешения наследуются, то есть entity3 наследует разрешения от entity2, entity2 наследует разрешения от entity1, если:

  3. Строки с совпадающим entity3 переопределяют строки с совпадающим entity2, которые переопределяют строки с соответствующим entity1.

В приведенном выше примере пользовательская группа 1 имеет запись для всех entity2 / entity3 в entity1 = 1 (1-я строка), за исключением entity2 = 1 и всех entity3 в entity2 = 1, для которых она прочитала (2-я строка) и т. Д.

Я уже написал логику (я думаю, что она не относится к актуальному вопросу, следовательно, не вставляя ее) как отдельный запрос, используя dense_rank - which is a window function.

Когда я использую эту логику напрямую с ОБНОВЛЕНИЕМ - она ​​работает безупречно.

Когда я встраиваю ту же самую логику, что и WITH CHECK политики безопасности на уровне строк - обновление отказывается обновлять строки (я включил БЕЗОПАСНОСТЬ УРОВНЯ СТРОКИ в соответствующих таблицах - так что это не так).

Я пытался встроить свою логику в функцию, а не прямо в политику, - но получил тот же результат, означающий, что это работает:

--not as table owner
update entity1
set col1=1
where entity1_id=10
and check_access(entity1_id); --updates 1 row

но это не так:

--as table owner
alter table entity1 enable row level security;

CREATE POLICY entity1_update
ON entity1 
AS permissive
FOR UPDATE
TO some_role
WITH CHECK ( check_access(entity1_id) );

--not as table owner
update entity1
set col1=1
where entity1_id=10; --updates no rows

Чтение документации: The conditional expression cannot contain any aggregate or window functions - это причина? Если это так - я ожидал, что при попытке создать политику или при запуске обновления возникнет ошибка, но ничего не происходит.

Я также попытался переписать свою логику проверки доступа, используя подзапрос с ORDER BY и обернув его с помощью LIMIT - не помогло.

Я что-то упустил? Есть ли способ обойти это?

1 Ответ

0 голосов
/ 10 января 2019

Я думаю, что нашел проблему - у меня есть другая политика FOR SELECT для той же таблицы, и я предположил, что ее предложение USING будет достаточным (есть AND между политиками разных FOR типов) - поэтому я не сделал включить условие USING в политику FOR UPDATE. Как только я добавил USING (true) в политику FOR UPDATE, все стало работать нормально (сейчас, по крайней мере, мне нужно больше экспериментов).

Похоже, это не имеет никакого отношения к использованию оконной функции.

  1. Я предполагаю, что postgres позволил мне создать политику FOR UPDATE без предложения USING, поскольку она допускает несколько политик одного типа - но, возможно, в документации должно быть примечание, что при наличии одного FOR UPDATE политика это ДОЛЖЕН включать оба пункта? ОБНОВЛЕНИЕ: Я не единственный, кто не смог обновить по той же причине - PostgreSQL, невозможно обновить строку (с безопасностью на уровне строк)

  2. Это заставляет меня спросить, что означает ограничение The conditional expression cannot contain any aggregate or window functions - если кажется, что оно работает с использованием dense_rank() over (order by...) ... поднято Ограничение агрегатных / оконных функций в условиях политики безопасности уровня строк Postgres

...