I am trying to wrap my head around row level security in Postgres. Unfortunately the documentation is not very verbose on the matter. My problem is the following:
I have two tables: locations
and locations_owners
. There is a TRIGGER
set on INSERT
for locations, which will automatically add a new row to the locations_owners
table including the request.jwt.claim.sub
variable.
This works all just fine, however when I want to create a policy for DELETE
like this:
CREATE POLICY location_delete ON eventzimmer.locations FOR DELETE TO organizer USING(
(SELECT EXISTS (SELECT name FROM protected.locations_owners AS owners WHERE owners.name = name AND owners.sub = (SELECT current_setting('request.jwt.claim.sub', true))))
);
It will always evaluate to true, no matter the actual content. I know that I can call a custom procedure with SELECT
here, however I ended up with the following questions:
- what is the scope of a
policy
? Can I access tables? Can I access procedures? The documentation says "Any SQL conditional expression" soSELECT EXISTS
should be fine - how are the column names of the rows mapped to the policy. The examples just magically use the column names (which I adopted by using the
name
variable), however I have not found any documentation about what this actually does - what is the magic
user_name
variable. Where does it come from? I believe it is the currentrole
which is executing the query, but how can I know? - why is there no
WITH CHECK
expression available forDELETE
? If I understand correctly,WITH CHECK
willfail
any row with invalid constraint, which is the behaviour I would prefer (because otherwise PostgREST will always return204
)
I am a little bit confused by the astonishingly missing amount of information in the (otherwise) very good documentation of PostgreSQL. Where is this information? How can I find it?
For the sake of completeness I have also attached the column definitions below:
CREATE TABLE eventzimmer.locations (
name varchar PRIMARY KEY NOT NULL,
latitude float NOT NULL,
longitude float NOT NULL
);
CREATE TABLE IF NOT EXISTS protected.locations_owners (
name varchar NOT NULL REFERENCES eventzimmer.locations(name) ON DELETE CASCADE,
sub varchar NOT NULL
);