To comply with privacy guidelines, I want to binary obfuscate the contents of certain columns to other roles, including the administrative role/developers.
A table could look like this:
create table customer (
id serial primary key,
role text not null default session_user,
name text not null,
address text not null,
phone bigint default null
);
create policy customer_policy on customer
for all to public using (role = session_user);
In this example, the column contents such as name, address and phone should not be visible to other roles.
the policy only guarantees that roles of other database users cannot see the records, but the administrator with higher privileges, for example, can still see the data.
my idea is that a password is stored in another table that is created and changed by the respective role. the relevant columns are then encrypted and decrypted using this password.
How could this be implemented or does PostgreSQL already offer solutions for this?
Related
I'm creating a website and I only want certain users to be granted the privilege of creating a post.
I have a table named Accounts where each user's basic information is stored (Id, firstName, lastName, email). Should I include a createPrivilege attribute in the Accounts table?
Or should I create a separate table named Privileges where I have the columns (id, createPrivilege) and the Id is a foreign key referencing the Accounts table's Id attribute?
If "createPrivilege" is an attribute of "Account", and there is only one instance of that attribute for any given entity, the common pattern is to have that as a column in the Account.
However, that approach quickly becomes very messy - you're likely to have many privileges, and adding new columns for each will make the "account" table very messy.
The most common way to model privileges is to introduce the concept of "role". A single user typically has several roles. A role might be "anonymous user", "authenticated user", "moderator", etc.
So, my recommendation would be to have a table with "account", a table called "role", and a join table "account_role" with foreign keys to both.
Assuming I have a (over simplified, non secure) table that looks like:
CREATE TABLE users (id SERIAL PRIMARY KEY, user VARCHAR(25), _password VARCHAR(25), email VARCHAR(80));
I want to add a additional failsafe on the column _password that prevents it from being returned on a SELECT * FROM users call, is this possible in PostgreSQL and if so, how?
I tried some versions of https://stackoverflow.com/a/7250991/929999, but this probably isn't what I was looking for. But that got me thinking that there might be a constraint that could be created. I can't find anyone who's tried this or asked it before, so I'm kind of lost seeing as I'm not a database expert by any means.
So for now I dump all results from the database into a custom dictionary placeholder in Python with a function called .safe_dump() that removes any keys starting with _<key>.
And I guess I could create a separate table containing a list of sensitive keys and match those on every SELECT statement via a JOIN or similar, but that would just move the risk of accidentally retrieving a sensitive key from the SELECT call to keeping that "JOIN table" updated.
Is there a flag in PostgreSQL that can filter out of block calls trying to access a key while still allowing it to be used on WHERE x=y clauses?
You can deny permission for that column:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
"user" VARCHAR(25),
_password VARCHAR(25),
email VARCHAR(80)
);
REVOKE ALL ON users FROM laurenz;
GRANT SELECT (id, "user", email) ON users TO public;
test=> SELECT * FROM users;
ERROR: permission denied for relation users
test=> SELECT id, "user", email FROM users;
id | user | email
----+------+-------
(0 rows)
If you'd rather want exclude the column from the output, use a view:
CREATE VIEW users_v AS SELECT id, "user", email FROM users;
GRANT SELECT ON users_v TO PUBLIC;
Pretend I have a users table where users are members of a specific tenant, and their e-mails are uniquely indexed to their tenant, like this:
User
id | tenant_id | email
1 1 person1#example.com
2 1 person2#example.com
This user is allowed because despite a duplicate e-mail, they are at a different tenant:
3 2 person1#example.com
This user is prevented because the e-mail is a duplicate at the same tenant:
4 2 person1#example.com <--- will throw an error
We have this much covered with a unique index -- that part is easy.
Now pretend that I want to be able to add a global user that can access all tenants, but only if the e-mail doesn't already exist in the table at all. Additionally, once the record exists, nobody else -- whether tenanted or not -- will be able to use the same e-mail.
For clarity, the global users could simply have a null tenant ID but we would likely also add a global boolean.
Is there a way to write constraints for this logic? You can't simply make e-mails globally uniquely constrained because they won't be able to be repeated across tenants, and if you index with a null tenant ID, postgres will allow an untenanted user if there are tenanted users with the same e-mail.
I've looked at exclusion constraints and checks but couldn't figure out how to combine them (uniquely constrain e-mail globally if tenant_id is null, and check for records with null tenant ID and matching e-mail when inserting any record).
Please don't ask why I'm doing things this way -- my table isn't actually users and we've considered and dismissed other architectures :)
Thanks in advance!
According to PostgreSQL Documentation you can create unique partial index which will be effectively the same as creating unique partial constraint on your table:
CREATE UNIQUE INDEX some_index ON some_table (col_a) WHERE (col_b is null);
Using this technique you can create 2 separate unique indexes for admin and non-admin users.
You can use a UNIQUE constraint for both fields:
create table myUsers
(
id int not null,
tenant int not null,
email varchar(200) not null,
UNIQUE(email, tenant)
);
insert into myUsers values
(1, 1, 'person1#example.com'),
(2, 1, 'person2#example.com');
insert into myUsers values
(3, 2, 'person1#example.com');
Next insert will throw an error:
insert into myUsers values
(4, 2, 'person1#example.com');
Error(s), warning(s):
23505: duplicate key value violates unique constraint
"myusers_email_tenant_key"
Check it here: http://rextester.com/AJZVI34616
For the second part of the question:
Now pretend that I want to be able to add a global user that can access all tenants, but only if the e-mail doesn't already exist in the table at all.
One solution could be to reserve a tenant for admin users:
tenant = 0 <-- admin users
But the UNIQUE constraint allow duplicated emails, I recommend you to add a rol field to this table, or have another table of admin users for this purpose.
In my case, we use two tables, and both have a rol field.
I am trying to get schema name in sybase database.
First I have create login(user1) from sa user and than i have connect with user1 by giving login name(user1) and password now i have tried to create table by giving following command:-
create table user1.table1(
emp_id int not null,
name varchar(80) not null
)
but it was showing access denied error than i have logged-in from sa user and grant sa_role to user1 and then again i have run above mention query for create table and table were created successfully.
here I am not exactly getting that user1 is schema name or not or how can I identified schema name?
I want to also know that is there any role except sa_role for grant create insert delete table ,views and all other objects of sybase database.
Sybase ASE does not use the schema concept that SQL Server and Oracle use. Objects are located inside a database, and owned by a user - no other logical separations are there. So your syntax is wrong.
create table table1
(
emp_id int not null,
name varchar(80) not null
)
Sybase ASE Create Table
Additionally, Sybase/SAP best practices tells us all database objects should be created/owned by dbo with permissions granted to groups/roles/users to access those objects. Users who own database objects can not be removed, so if User1 gets fired, you will have to identify all the objects he owns, and change the ownership of those objects before his account can be deleted.
So for your example, the dbo user (typically sa) would create the objects, then GRANT permissions (INSERT/UPDATE/DELETE/etc) to the groups/roles/users who need access.
More information on managing user permissions can be found in the Sybase ASE System Administrators Guide Vol 1.
And more information about Roles/Groups from the System Admin Guide.
So, i'm currently working with a database system where a user can register, login and update his/her details whenever.
The database includes 5 roles:
1. Public
2. Member
3. Moderator
4. Coordinator
5. Admin
I want to be able to assign multiple roles to my users. For example, the Admin can also be a member. Therefore in the database it should show:
User_id | Role_ID
------------------------
user1 | 2, 5
^ is it possible to add multivalued id's in postgresql?
You can use filed of type array to store list of values.
However I think that there is much better way to organize what you want.
Make one table: role_names and another roles, like that:
CREATE TABLE role_names
(
id serial NOT NULL,
name text NOT NULL,
CONSTRAINT role_names_pkey PRIMARY KEY (id),
CONSTRAINT role_names_name_key UNIQUE (name)
);
CREATE TABLE roles
(
user_id bigint NOT NULL,
role_id bigint NOT NULL,
CONSTRAINT roles_pkey PRIMARY KEY (user_id, role_id),
CONSTRAINT roles_role_id_fkey FOREIGN KEY (role_id)
REFERENCES role_names (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE RESTRICT
);
Now in the table role_names you put all the roles that you want to have.
In the table roles, you can assign or delete any number of roles to any user.
Also you can search in table roles for specific users or specific roles - much neat and faster than searching into arrays I think.
Feel free to add FK constraint for the user_id field too.
Yes, you can use int array to store list of roles.
Here's related question -Junction tables vs foreign key arrays?