BogDan, Thanks for your interesting.

At first, I would like to confirm whether you know the row-level security
feature is postponed to v8.5, or not. Thus, the latest patch set (toward
v8.4 development cycle) does not contain the row-level one.
Please note that the following my comments assume the separated feature.

BogDan Vatra wrote:
Hi,

        I need SE-PostgreSQL *ONLY* for row level security, but AFAIK 
SE-PostgreSQL
works only on SELinux. This, for me,  is unacceptable, because I want to use
row level security on windows too.  I don't need all that fancy security
stuffs.

In my understanding, the row-level ACLs feature (plus a bit enhancement) can
help your requirements. I developed it with SE-PostgreSQL in parallel, but
also postponed to v8.5 series.
It enables to assign database ACLs on individual tuples, and filter out
violated tupled from the result set of SELECT, UPDATE and DELETE.

So, it is not very hard. At least, we already have an implementation. :)
> -real cross platform row level security, this seems to be very hard to do.


I want to share with you my "security" experience, my English is not so good
so, to be more clear, I give you an example and show you what I do instead
row
level security.
In this example I need row level security because I want an user who is
logged
in to see only a portion of a table (some filtered rows).

Let's say we have 2 tables:
1. customers
2. customers_products
and I want to let the user to select,insert, update or delete only what they
operate.

I guess you concerned about:
- It is necessary to set up many trigger functions for each tables, which
  provide similar functionality.
- Users have to specify different names between reference and modification.

And, you want to make clear how the row-level access control resolves it.
Is it OK?

Your requirement is a simple separation between different users.
Thus, what we have to do is:
 - When a tuple is inserted, the backend automatically assigns an ACL which
   allows anything for the current user, but nothing for others.
 - So, when user tries to select, update and delete this table, tuples which
   inserted by others to be filtered out from the result set or affected rows.
 - Normal users are disallowed to change automatically assigned ACLs.
   (I don't think you want to restrict superuser's operations.)

The row-level ACLs have a functionality named as "default acl".
It enables table's owner to specify ACLs to be assigned to newly inserted
tuple, like:

  CREATE TABLE customer_products (
     id serial,
         :
  ) WITH (default_row_acl='{rwd=kaigai}');

Currently, it does not allow replacement rules like "{rwd=%current_user}",
but it is not a hard enhancement. If such an ACL is assigned, the tuple
is not visible from other users without any triggers.

  For example, please consider when a user "kaigai" insert a tuple into
  "customer_products", the "{rwd=kaigai}" is assigned to the tuple, but
  the "{rwd=bogdan}" is assigned when a user "bogdan" do same thing.

In this case, any users must not be an owner of the table, because owner
of the table is allowed to change the ACLs.

This is an aside. If you want different access controls, like read-only
for other's tuples but read-writable for own tuples, it will be possible
with different default acl configuration.

Does it help you to understand about the row-level security currently
we are in development?

Thanks,


[SQL]

CREATE TABLE customers -- this is my "customers" table
(
   id serial,
   curstomer_name text,
   login_user name DEFAULT session_user,  -- the user who have the permission
to see this row
    PRIMARY KEY (id)
) ;
ALTER TABLE customers OWNER TO postgres; -- the table is "invisible" to
normal
users
GRANT UPDATE, INSERT, DELETE, TRIGGER ON TABLE customers TO public; -- but
they can UPDATE, INSERT, DELETE and TRIGGER the table.

GRANT USAGE ON TABLE customers_id_seq TO public;

-- this is my solution to "row level security", user can query this view
only,
the table is "invisible" to them.
CREATE OR REPLACE VIEW view_customers AS
select * from customers where login_user=session_user;


CREATE TABLE customers_products
(
   id serial,
   id_customer integer NOT NULL,  -- the customer id
   product_name text NOT NULL,
   login_user name DEFAULT session_user, -- the user who have the permission
to see this row
    PRIMARY KEY (id),
    FOREIGN KEY (id_customer) REFERENCES customers (id)    ON UPDATE CASCADE
ON DELETE CASCADE --here it will be more useful if I can REFERENCE the view.
);
ALTER TABLE customers_products OWNER TO postgres; -- the table is "invisible"
to normal users
GRANT UPDATE, INSERT, DELETE, TRIGGER ON TABLE customers_products TO public;
-- but they can only UPDATE, INSERT, DELETE and  TRIGGER the table.
GRANT USAGE ON TABLE customers_products_id_seq TO public;

-- this is my solution to "row level security", user can query this view
only,
the table is "invisible" to them.
CREATE OR REPLACE VIEW view_customers_products AS
select * from customers_products where login_user=session_user;


-- This trigger is executed every time you insert,update or delete from
table.

CREATE OR REPLACE FUNCTION customers_products_row_security()
  RETURNS trigger AS
$BODY$
BEGIN
IF (TG_OP = 'DELETE') THEN
        if OLD.id_customer NOT IN (SELECT id from view_customers)THEN
                RETURN NULL;
        END IF;
RETURN OLD;
END IF;
IF NEW.id_customer NOT IN (SELECT id from view_customers) THEN
        RETURN NULL;
END IF;
NEW.login_user:=session_user;
RETURN NEW;
END;
$BODY$
  LANGUAGE 'plpgsql' VOLATILE SECURITY DEFINER;
ALTER FUNCTION customers_products_row_security() OWNER TO postgres;
GRANT EXECUTE ON FUNCTION customers_products_row_security() TO public;

CREATE TRIGGER customers_products_row_security_trigger BEFORE INSERT OR
UPDATE
OR DELETE
   ON customers_products FOR EACH ROW
   EXECUTE PROCEDURE public.customers_products_row_security();

[/SQL]

Another trigger should be created on customers table but you've got the
point.
As you can see there is a lot of code and possibility to make many mistakes.
What I my humble wish?
I wish I can make this more simple and elegant.
Here I see 2 solutions.
-real cross platform row level security, this seems to be very hard to do.

- the possibility to  create "FOREIGN KEY"s who reference views or the
possibility to "CHECK" a cell of a row with a subquery in our example
something like this:"CHECK (id_customer IN (select id from view_customers))".
If I'll have this feature I don't have to create that triggers anymore.  I
hope this is more simple for you to create.


Yours,
BogDan Vatra,






--
OSS Platform Development Division, NEC
KaiGai Kohei <kai...@ak.jp.nec.com>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to