How to check if the current user inherits the BYPASSRLS attribute from a role? - postgresql

I need to check whether row-level-security applies to the current_user in a Postgres query. As far as I can tell, I need to check whether the current user is the owner of that table, or has the BYPASSRLS attribute, or is member of a role that has this. That group membership check seems cumbersome though, especially considering the NOINHERIT attribute of some roles… How to achieve this?

I need to check whether row-level-security applies to the current_user
Indeed there is a much simpler way to check that - in particular for a specific table, which the user (or one of the inherited roles) might be owner of. The solution is to use the row_security_active function:
row_security_active checks whether row level security is active for the specified table in the context of the current_user and environment. The table can be specified by name or by OID.
So just use
SELECT row_security_active('schema.table');

Related

Delete row despite missing select right on a column

In this example, the second column should not be visible for a member (role) of the group 'user_group', because this column is only required internally to regulate the row level security. however, records can only be deleted if this column is also visible. How can you get around that?
Options that come to mind would be:
just make the second column visible (i.e. selectable), which would
actually be completely superfluous and I want to hide internally as
much as possible
write a function that is called with elevated rights
(security definer), which I want even less.
Are there any other options?
(and especially with deletions I want to use nice things like 'ON DELETE SET NULL' for foreign keys in other tables, instead of having to unnecessarily program triggers for them)
create table test (
internal_id serial primary key,
user_id int not null default session_user_id(),
info text default null
);
grant
select(internal_id, info),
insert(info),
update(info),
delete
on test to user_group;
create policy test_policy on policy for all to public using (
user_id = session_user_id());
RLS just implicitly adds unavoidable WHERE clauses to all queries, it doesn't mess with the roles under which code is evaluated. From the docs:
"Since policy expressions are added to the user's query directly, they will be run with the rights of the user running the overall query. Therefore, users who are using a given policy must be able to access any tables or functions referenced in the expression or they will simply receive a permission denied error when attempting to query the table that has row-level security enabled."
This feature is orthogonal to the granted column permissions. So the public role must be able to view the user_id column, otherwise evaluating user_id = session_user_id() leads to an error. There's really no way around making the column visible.
completely superfluous and I want to hide internally as much as possible
The solution for that would be a VIEW that doesn't include the column. It will even be updatable!

Readonly admin user in postgresql

we have a postgres database we want to run a number of checks against. Part of the tool involves looping over database all the database tables and views, checking grants and other things - so it would be entirely pointless if we had to grant access to this user to individual tables.
We want to be able to create a user that has full read privileges to anything, regardless of what permissions are set in the database - like a db owner - but has no write access at all.
Is this possible in any way?
The only way to do this is granting the SELECT privilege on every individual object that needs to be examined. You can make the work easier with
GRANT SELECT ON ALL TABLES/SEQUENCES/... IN SCHEMA ... TO ...;
You can also use ALTER DEFAULT PRIVILEGES to set the permissions on future objects.
I recommend that you create a readonly role and do all that once. Then you can create a read-only user by making the user a member of that role.
With postgresql 14 you can just do:
GRANT pg_read_all_data TO my_role;
https://www.postgresql.org/docs/14/predefined-roles.html

Postgresql role with no drop table permision

Is it possible to set role with access to one database, with all privileges except to drop tables?
Not really. If a user can issue CREATE TABLE, it can issue a DROP for that table as well. From the docs:
The right to drop an object, or to alter its definition in any way, is not treated as a grantable privilege; it is inherent in the owner, and cannot be granted or revoked.
And as noted by the CREATE TABLE docs:
The table will be owned by the user issuing the command.
There is no mechanism to allow a user to create tables that they do not own and therefore cannot drop.

PostgreSQL Error [42501]: ERROR: must be owner of relation table

I am maintaining a database 'db' in which there are around 100 tables.I have one super user 'A' and 'A' is the owner of all tables. How can I give Alter permission to new user 'B' specific to single table without inheriting all permissions from 'A'.
I tried by providing Grant A to B;. This Grant option given all permissions from 'A' to 'B'. I want above scenario to restrict to one particular table.
Is this possible?
The documentation recently acquired this explanation:
The right to modify or destroy an object is inherent in being the object's owner, and cannot be granted or revoked in itself. (However, like all privileges, that right can be inherited by members of the owning role; see Section 21.3.)
So the only people who can run ALTER TABLE are:
Superusers
the table owner
members of the table owner role
So GRANT a TO b is the only way to give somebody the privilege.
You might be able to use a SECURITY DEFINER function that belongs to a, but be careful with that.

Preventing ALTER TABLE on PostgreSQL 9.4 even by the owner

We're using PostgreSQL 9.4.
We need to prevent users from doing an ALTER on a table, not even the owner of the table.
The owner of the table would have to 'grant' himself the permission to do the ALTER.
I imagine it would be like setting a 'read only flag' on the table's schema.
The table in question is being inherited from another table, if this has any importance.
The ideal solution would allow to do a message like "You can't ALTER the table because .... "
Is this achievable? and if so, how?
This is probably not what you actually want, but a potentially interesting effect:
When creating an inherited table, you have to do it as the owner of the parent table, but you can then change the owner of the child table. The new owner won't be able to drop/modify the inherited set of columns, though will still be able to change defaults/checks/triggers/etc, and to add new columns.
The simplest way to do something close to what you actually want is probably to control access by the owner role: create a separate role to access the tables, and revoke the CONNECT privilege on the database from the owner.