How to revoke copy access to a user postgres? - postgresql

I want to have a role based access for my Database. I've created a new user and want this user to only select access on Table but this also comes copy by default. I want to revoke this copy access to this user. Any help in this context would be really appreciable.
Thanks a Lot!!!

PostgreSQL does not directly support what you want - and it's pretty dubious theoretically, too.
Even if you modified PostgreSQL to add a COPY permission, the user would just use the XML table functions, the new JSON support, or a plain old SELECT ... FROM tablename; to extract the data.
If somebody has SELECT rights to a table, they can COPY ... TO stdout that table and they can SELECT ... INTO another table if they have CREATE rights anywhere. This makes sense; after all, they can always SELECT * FROM tablename; and process it client-side.
You can selectively GRANT rights on individual columns, but they can still do a SELECT allowedcol1, allowedcol2, ... FROM tablename and therefore a COPY (SELECT allowedcol1, allowedcol2, ... FROM tablename) TO stdout.
The only way to (mostly) stop a user from doing a COPY or SELECT INTO is to force all access through SECURITY DEFINER stored procedures that define very limited acess to the table.
A clever user can still write a COPY (SELECT ...) TO stdout with a query that uses your stored procedure API to loop over keys and request each one. It'll be slower, but so long as you provide any way to list all the keys in the table it will work.
In the end, if you give them SELECT you give them the ability to copy one way or the other.

Related

How to restrict a user from executing a COPY query in PostgreSQL?

I need to restrict a user in pgsql from executing copy statement. I can disallow execution of any of the CRUD operations.
COPY command can read from a table to somewhere or it can write to a table from somewhere (from file, another table or from a query).
I assume you want to restrict writing to any table.
In this case, just restrict UPDATE/INSERT/DELETE operations for that user:
revoke insert, delete, update on all tables in schema public from xxx;
Double-check that your user is not a superuser (in this case, all permissions checks are just ignored; so if it is, just alter role xxx nosuperuser;).
It's also worth to define default strategy for all new tables, revoking writing access from this role:
alter default privileges in schema public
revoke insert,update,delete on tables from xxx;
If you want to restrict reading with COPY from any table (like copy (select * from table1) to stdout;), you need also revoke reading access (i.e. SELECT permission) from all objects.
Note, that there is a variant of COPY which will work nevertheless – if it reads from "nowhere", i.e.:
copy (select 'blabla') to stdout;
or
copy (values('blabla')) to stdout;
or, even more extreme version, reading "nothing":
copy (select) to stdout;

How do I protect specific columns from having their values explicitly set via a REST API update?

I have multiple tables that I would like users to be able to update through the rest api, and many (if not all) have columns with sensible defaults.
The web app itself can be designed to hide these columns, but I want to allow direct access to the api as well so that others can make use of the data however they see fit.
Unfortunately, this means they can set the defaulted columns explicitly (set timestamp columns to 1972, or set id columns to arbitrary values).
What mechanisms are available to restrict this on the backend (Postgres 9.4)?
You should do this at API level.
If anybody issues a malformed request (e.g. they want to overwrite an ID or a timestamp), answer with a proper status code (perhaps 400), amended with a meaningful message, for instance "Hey you tried to update , which is read only."
If you would really insist to handle it at db level, here they suggest that:
The easiest way is to create BEFORE UPDATE trigger that will compare OLD and NEW row and RAISE EXCEPTION if the change to the row is forbidden.
I've had some luck experimenting with Postgres' column-level grants. It's important in a development environment to make sure that your database users isn't a superuser (if it is, create a second superuser, then revoke it from the dev account with alter role).
Then, commands similar to these can be run on a table:
revoke all on schema.table from dev_user;
grant select, delete, references on schema.table to dev_user;
grant update (col1, col2) on schema.table to dev_user;
grant insert (col1, col2) on schema.table to dev_user;
Some caveats:
Remember to grant "references" as well if another table will fkey to it.
Remember to give col1 and col2 (and any other) sane defaults, because the API will be unable to change those in any way.
DO NOT FORGET TO CREATE A SECOND SUPERUSER ACCOUNT BEFORE REVOKING SUPERUSER STATUS FROM THE DEV ACCOUNT. It is possible to recover this, but a big pain in the ass.
Also, if you're keeping these grant/revocations in the same file as the create table statement, the following form might be of use:
do $$begin execute 'grant select, delete, references on schema.table to ' || current_user; end$$;
This way the statements will translate correctly to production, which may not use the same username as in development.
PostgreSQL since version 9.3 supports updatable views, so instead of exposing actual table you can expose a view with a limited subset of columns:
CREATE TABLE foo (id SERIAL, name VARCHAR, protected NUMERIC DEFAULT 0);
CREATE VIEW foo_v AS SELECT name FROM foo;
Now you can do things like:
INSERT INTO foo_v VALUES ('foobar');
UPDATE foo_v SET name = 'foo' WHERE name = 'foobar';
If you need more you can use INSTEAD INSERT/UPDATE RULE or INSTEAD OF INSERT TRIGGER.

How to revoke right to a usergroup on a certain date in postgresql?

I'm currently creating a DB with Postgresql. First time, be gentle. ;)
I have a table project that stores submission date among other things.
I have 2 groups of users. One can only consult the database, no update/insert/delete rights, so it's quite easy.
The other group has the rights to do whatever they want on their project, but only until the submission date.
I'm looking for a nice way to do it.
I thought at a trigger function that checks the current_date and the date stored in the DB, and revokes the rights if it is passed, then raise an exception 'You don't have the rights anymore to modify that project.
I could use that same trigger on all my tables.
I think that could work, but I don't know if that the right/nice way to do it.
PS: If someone also has some tip about 1..* to 0..* relation…
Privileges are granted per object. You cannot grant privileges per row directly with GRANT / REVOKE.
One way around this would be a VIEW that only shows not-yet-submitted projects. Simple for SELECT privileges, more complicated for UPDATE / DELETE. You'd need INSTEAD rules on the view, which gets tricky, especially for beginners.
The other obvious option is what you already had in mind, just simpler. You don't have to actually revoke privileges. Just throw an exception for submitted projects:
CREATE OR REPLACE FUNCTION trg_p_updelno()
RETURNS trigger AS
$func$
BEGIN
IF pg_has_role('other_group', 'member')
AND OLD.submission_date < now()::date THEN
RAISE EXCEPTION 'Too late, Kate! Project already submitted.';
END IF;
RETURN NULL;
END
$func$
LANGUAGE plpgsql;
CREATE TRIGGER updelno
BEFORE UPDATE OR DELETE ON project
FOR EACH ROW
EXECUTE PROCEDURE trg_p_updelno();
pg_has_role() is one of the Access Privilege Inquiry Functions, which should come in handy.
Of course, you would want to keep those users from editing the submission date. You could do that in the trigger as well.
But be careful when referring to NEW in a trigger function that can be fired ON DELETE, where NEW does not exist. Have a look at the examples in the manual using TG_OP here.
One thing you can consider is that if group two is going to have no access to the db after a specific date, you can revoke their login permissions at that point. Note how depends on authentication specifics but if it is password login, you just:
ALTER USER foo VALID UNTIL '2013-07-01';
Note this only expires the password. You could then have a cron job which goes through periodically and cleans up expired users (info is in pg_authid system table).
If the users will still have access to the PostgreSQL instance, you will need to go with Erwin's suggestions.

how to grant update or select on some specified row in postgresql table?

I want to create some roles in my Postgresql DB and grant some access.
I have student role and i want to grant this user type : can edit only record a bout him/her in student table and can not edit other rows
how can i do it?
thanks
Create a view on the table with an appropriate where clause, then grant access to that:
create view students_view as
select col1, col2, col3 -- limit column access here
from mytable
where <whatever>; -- limit row access here
-- limit what he can do here
grant update, select to student_role;
BTW It is a commonly held misconception that you can't update a view, but that is only true if the view is a join or similarly complicated query.
PostgreSQL doesn't have row-level declarative security (yet, there's ongoing work into it) so if you can't just create a view - say, if you have many different people who need this access - you will probably need a SECURITY DEFINER helper function or trigger.
You've got a couple of options:
Write a SECURITY DEFINER function that lets them make only the permitted changes and limit their access to the table to SELECT, revoking UPDATE, DELETE, TRUNCATE and INSERT rights; or
write a trigger that tries to restrict them from making changes you don't want them to make and GRANT them write access to the table.
Of the two, the function and restricted rights approach is by far the safest option so long as you follow the SECURITY DEFINER secure coding guidelines set above - setting search_path for the function, avoiding dynamic SQL (EXECUTE) with string substitutions, etc.
The view approach given above can work quite nicely if it's a view that filters by current_user. You may also want to look at the new SECURITY BARRIER views; see this post for a useful discussion of them.
GRANT UPDATE(column) on tabela to user_name;

Sybase IQ: Granting a right on tables of one user to anther user

I'm looking for a way to grant some right (say SELECT) on all tables of one user to some other user.
Something like that:
GRANT SELECT ON Username1.* to Username2
Important condition is that I need not only granting the right to all existing tables, but I also want, that all tables that will be created by Username1 by default should be granted with correspondent right to Username2
What I've done is creation a an external script for choosing all tables created by Username1:
SELECT table_name FROM systable WHERE creator IN (SELECT user_id from sysuser WHERE username='Username1'))
and generating GRANT statements for every of them.
But than I need to execute that script as soon as new table is created.
It is not really elegant to have that granting logic out of the database.
I would prefer having kind of trigger within the database, but Sybase IQ does not support triggers.
Anybody have idea how to solve the problem in elegant manner?