简体   繁体   中英

What is the scope of Postgres policies?

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" so SELECT 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 current role which is executing the query, but how can I know?
  • why is there no WITH CHECK expression available for DELETE ? If I understand correctly, WITH CHECK will fail any row with invalid constraint, which is the behaviour I would prefer (because otherwise PostgREST will always return 204 )

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
);

Many of the questions will become clear once you understand how row level security is implemented: the conditions in the policies will automatically be added to the query, just as if you added another WHERE condition.

Use EXPLAIN to see the query plan, and you will see the policy's conditions in there.

  • So you can use any columns from the table on which the policy is defined.

    Essentially, you can use anything in a policy definition that you could use in a WHERE conditions: Function calls, subqueries and so on.

    You can also qualify the column name with the table name if that is required for disambiguation. This can be used in the policy from your example: The unqualified name is interpreted as owners.name , so the test always succeeds. To fix the policy, use locations.name instead of name .

  • There is no magic user_name variable, and I don't know where you get that from. There is, however, the current_user function, which is always available and can of course also be used in a policy definition.

  • WITH CHECK is a condition that the new row added by INSERT or UPDATE must fulfill. Since DELETE doesn't add any data, WITH CHECK doesn't apply to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM