Политика и функции Postgres RLS

#postgresql #postgraphile

Вопрос:

У меня есть нарушение политики RLS в функции Postgres. Я считаю, что это связано с тем, что политика основывается на строках, созданных в функции. В SELECT функции выполняется команда. Новые строки недоступны, поскольку они все еще находятся в транзакции.

Вот функция:

 CREATE FUNCTION public.create_message(organization_id int, content text, tags Int[])
RETURNS setof public.message
AS $

-- insert message, return PK
WITH moved_rows AS (
  INSERT INTO public.message (organization_id, content)
    VALUES($1, $2)
  RETURNING *
),

-- many to many relation
moved_tags AS (
  INSERT INTO public.message_tag (message_id, tag_id)
  SELECT moved_rows.id, tagInput.tag_id
  FROM moved_rows, UNNEST($3) as tagInput(tag_id)
  RETURNING *
)

SELECT moved_rows.* FROM moved_rows LEFT JOIN moved_tags ON moved_rows.id = moved_tags.message_id

$ LANGUAGE sql VOLATILE STRICT;
 

Вот политика:

 CREATE POLICY select_if_organization
      on message_tag
      for select 
      USING ( message_id IN (
        SELECT message.id 
          FROM message
          INNER JOIN organization_user ON (organization_user.organization_id = message.organization_id) 
          INNER JOIN sessions ON (sessions.user_id = organization_user.user_id)
          WHERE sessions.session_token = current_user_id()));
 

Идеи:

  1. Добавьте поле в таблицу объединения, чтобы упростить политику, но это нарушает обычную форму.
  2. Возвращайте пользовательский ввод вместо запуска SELECT, но ввод может быть экранирован, и я смогу выполнить SELECT команду
  3. Разделен на две функции. Создайте message строку, затем добавьте message_tag . Я запускаю постграф, так что две мутации. У меня есть внешние ключевые отношения между ними. Я не знаю, будет ли graphile делать это автоматически.

Сообщение об ошибке:

 ERROR:  new row violates row-level security policy for table "message_tag"
CONTEXT:  SQL function "create_message" statement 1
 

Я получаю сообщение об ошибке при запуске функции. Я хочу, чтобы функция успешно запустилась, вставила одну строку в message таблицу и превратила входной массив в строки для message_tag таблицы с message_tag.message_id=message.id последним вставленным идентификатором. Мне нужна политика, чтобы пользователи из этого отношения присоединения видели только строки своей организации message_tag .

Вот еще одна политика в отношении команды INSERT. Это позволяет ВСТАВЛЯТЬ, если пользователь вошел в систему:

 create policy insert_message_tag_if_author
  on message_tag
  for insert
  with check (EXISTS (SELECT * FROM sessions WHERE sessions.session_token = current_user_id()));
 

Комментарии:

1. Ваша функция RETURNS setof public.message . Какой вообще смысл присоединяться к результату против moved_tags ? Это только приведет к дубликатам. Вместо этого верните вставленное сообщение (которое, вероятно, должно быть единственным), а затем выберите теги этого, используя graphql. Это гарантирует message_tag , что запрос к таблице будет отправлен только после вставки всех строк.

2. «У меня есть нарушение политики RLS в функции Postgres. «- в чем именно заключается ошибка? Какие результаты вы получаете, когда вызываете функцию? Каков ожидаемый результат?

3. @Bergi Спасибо. В этом есть смысл. В графическом файле есть поле запроса в полезной нагрузке мутации.

4. Я удалил возвращающую инструкцию SELECT, но по-прежнему получаю ошибку. Похоже, это ВСТАВКА. Я обновил вопрос, добавив, пожалуйста, дополнительную информацию.

5. Что делать, если я создам новую политику на основе значения конфигурации, заданного в функции? Перед вставкой установите значение конфигурации в значение true. После этого установите для него значение false.

Ответ №1:

Согласно сообщению об ошибке, эта часть вашей инструкции SQL вызывает ошибку:

 INSERT INTO public.message_tag (message_id, tag_id)
  SELECT moved_rows.id, tagInput.tag_id
  FROM moved_rows, UNNEST($3) as tagInput(tag_id)
  RETURNING *
 

Вам необходимо добавить другую политику FOR INSERT с соответствующим WITH CHECK пунктом.

Комментарии:

1. Я никогда раньше не видел ан И в А. Когда я попытался это сделать, я получил синтаксическую ошибку, указывающую прямо на «И». Я скопировал свою политику и добавил ее для ВСТАВКИ, но с той же ошибкой. У меня также есть другая политика, которая просто проверяет наличие сеанса пользователя при ВСТАВКЕ. Я думаю, что это связано с несуществующей строкой, потому что она находится в середине функции. Я запускаю команды отдельно в CLI, и это работает.

2. Я забыл, что полис может быть только один FOR . Вам придется добавить вторую политику. Сообщение об ошибке однозначное, оно жалуется на незаконное INSERT . Вы не показали ту другую политику, поэтому я не могу сказать, что именно не так.

3. Я обновил вопрос с помощью другой политики. Один из моих успехов заключается в запуске функции SELECT set_config(‘политика. allow_message_tag’, ‘t’, true). Затем, имея политику, которая позволяет вставлять, если задана эта конфигурация. В конце функции я вернул эту конфигурацию на «f». Похоже, он работает в командной строке, но не с конечной точки графического файла, над которой я работаю.

4. Тогда именно эта политика терпит неудачу. current_user_id() должна быть определяемая пользователем функция. По крайней мере, вы знаете, в каком направлении отлаживать.

Ответ №2:

Я закончил тем, что добавил поле в присоединяемую таблицу и с его помощью создал политику. Таким образом, для проверки RLS не требуется строка, которая была бы создана в середине функции.