PostgreSQL: create a personalized role for any customer - postgresql

I am new to Postgres, sorry if the question is basic:)
I need to create a personalized role for any customer already existing in the DB.
Role name must be client_{first_name}_{last_name} (without curly brackets).
Also, this customer can only access his own data in "table_1" and "table_2" tables.
I took ALICE STEWART (id 51).
What I did:
I created role Customer with Select privilege. Then tried to create role for ALICE STEWART and I get an infinite recursion error.
But how to create role for one customer so that he could access only his info in 2 tables?
How to do that properly?

There is nothing wrong with personalized database users, but I would only consider that if you don't have very many users. I wouldn't want to deal with a pg_authid that contains 100000 users.
I would not play this with permissions, but with row level security. The exact way in which that would work depends on your data. The easiest way is to have and owner column that lists the user that can see the data.
Watch out for overly complicated policies, as they will make your queries slow.

Related

Designing a role based access on DB level

I am working on designing role based access for an application. Here, there are various department like HR, Finance , Developer ,etc. I am planning to have department level accesses on their respective related table like Finance user can access Payroll table...
I have done some R&D and came up with following approach.
Currently I have thought to have Department level user roles.
I have planned 3 roles Viz. super admin ,admin & user. So lets suppose if HR user makes a request to write data on employee we can check if user is from HR and then we grant this access.
Problem is that I am not able to design how to place an access table which can have collection of all accesses like employee_read_write or payroll_read_write ,etc.
Should I be creating a new access & map it somehow to user roles & department OR map the different tables that can be accessed on department level like Finance department has payroll accesses.
Since, I am new to RBAC kindly let me know if this is the right approach that I am planning or there is some better way. Appreciate your inputs !!

Role based system in Tree User Structure

So I am using Node/MongoDB (mongoose) to implement this feature.
What I need is the right solution for the following problem:
We have many Company(ies)
Each Company can create it's own Roles
Role is a set of predefined Permissions (like task.create, task.read, task.update, task.delete)
They can choose which Permissions are included in which Role
Company can create it's own Users, and assign them a Role
Lets say that company created 3 roles (the order matters):
Owner (always predefined, has all Permissions)
Team Leader
SuperAgent
Agent
Beside that, I also have Users in a tree structure, with parent reference which holds the _id of the User above him.
The rules are:
User can have none or many children
User cannot be above someone that have higher role than him
User cannot be below someone that have lower role than him
The Tree can get as deep as they want...
So the right representation of this would be:
But because Company Owner can at any time make new Role, or switch the order of roles, the problem occurs...
Let's say he switched the places of 2 roles, and they are now:
Agent
SuperAgent
How would you update all Users?
Also, what if he creates a new Role, puts it in 3rd place, and now needs to update everyone 1 role below, so he can attach that new role to a user...
What approach would you take to solve this kind of issue?

How to implement complex permission based data access in Postgres with Postgraphile or alternatives

For a new project, we're currently designing a database and an API to access this. We've already established we'll be using PostgresQL for the database, and want to access it via a GraphQL API.
To ease with maintainability, we looked at several intermediaries between client/API/database, mainly Prisma, PostGraphile and Hasura. PostGraphile stood out, because of ease of use and the focus of handling stuff "in database" as opposed to in your backend code. However, we ran into issues when figuring out how to implement this.
Allow me to expand on what we designed thus far:
Provisional database design:
users table
groups table
roles table:
u_g_r table: A user can be part of multiple groups, and can have multiple roles in each group. This table represents foreign keys for users, groups and roles, as many-to-many relations can exist in virtually all combinations.
Data Permissions:
We want users to grant others access to their personal data in several steps, preferably for each group. For example:
level 3: Yourself and only absolutely necesary people, such as account manager
level 2: Only people in group X, Y, etc
level 1: Everybody
It would be awesome if it was possible to set this for various types of data, for example grant level 2 for your phone number, but only level 1 for your physical address.
So, these levels (1, 2, 3) would accompany data in the database, like phone_number and phone_number_access_level for example. Then, in the u_g_r junction table, each combination of user/group/role would have an allowed level attached to it, which must be higher than the required level for the relevant data. Thus, if your role allowed access to data on level 2, you would be able to view data on level 1 and 2, but not level 3.
Postgres allows both column- and row level security, to let users access certain data. The PostGraphile wiki goes into some detail (here and here) how you would make this work with JWT claims instead of PostGres roles.
Our problem arrives when we want to implement the above features. It seems we want a kind of 'field level security' that does not exist, but I can't imagine others not having had the same issues.
What would you advive us to do? Please let me know if there are options we've missed, or whether there are other options that are better for us!
Implementing this outside the database, in backend code might might be the easiest way in and of itself, but it greatly impacts maintainability for us, as the main luxury of things like PostGraphile for us is removing the need to write GraphQL schema's and resolvers ourselves.
It seems that you want all users to see all table rows, but only certain columns.
You probably cannot use column permissions, because these can only allow or deny access to the column as a whole and do not respect who “owns” a certain table row.
So perhaps views can do what you want, for example:
CREATE VIEW users_view
WITH (security_barrier = true, check_option = local) AS
SELECT /* accessible to everyone */
username,
/* accessible only to certain groups */
CASE WHEN pg_has_role('x', 'USAGE') OR pg_has_role('y', 'USAGE')
THEN level2_col
ELSE NULL
END AS level2_col,
/* accessible only to admins and owner */
CASE WHEN username = current_user OR pg_has_role('admin', 'USAGE')
THEN level3_col
ELSE NULL
END AS level3_col
FROM users;
security_barrier makes sure that nobody can use functoins with side effects to subvert security, and check_option ascertains that nobody can INSERT a row that is not visible to themselves.
You can allow DML operations on the views if you define INSTEAD OF triggers.
Based on the answer of Laurenz Albe, I created an immense view for all kinds of columns. It worked, certainly, and even with several thousands of entries of mock data it was still relatively quick.
When I got back to it last week, a cleaner solution (arguably) dawned on me. Instead of using custom views like this, I'm now using separate tables with the sensitive data, link them with foreign keys and enable Row Level Security on these rows.
I haven't done any benchmarks, but it should be faster as this data isn't always requested anyways. It at least saves complicated views with a lot of boilerplate!

SQL Server - Return rows based on user role

We are developing an Access application with a SQL Server backend. We have a table that has records that belong to division A, B or C. The users also belong to role A, B or C. We want each user to see only their corresponding division records, as well as only certain columns.
I've thought of two ways, one making different queries for each role and then, based on the user's role, change the source object of the form. However I don't know if it is possible to retrieve it from SQL SERVER with VBA (all VBA documentation I've found so far is quite lacking).
The other solution I thought was to implement this on the server, however I don't know how a T-SQL query or view could fetch only the information needed based on the user's role
Any ideas?
PS: I can't use functions or stored procedures. For some reason the SQL Server we have been provided has them disabled and IT Ops won't enable them (Don't know the logic behind that).
Okay, it's been a while since I posted this but I'll post the solution I came up with in the end. VBA is not quite necessary in this case. It can be done perfectly with views.
To retrieve the users roles, (inner) join the table database_role_members twice with the database_principals one. Join by Id (from database_principals) on both fields. With this, you get a list of all roles and their corresponding users. To get the roles of the user querying the database simply add a where clause that checks that the user name corresponds with the function USER_NAME.
Then, don't give permission to those roles to access the table we want to restrict access to. Instead, make a view that fetches info from that table and add a where clause that looks up the value from a column against the query that retrieves the user roles.
With this you can make a link in access to the view and will allow you to see only the records that correspond to the user roles.
While this approach is easy, it doesn't allow for more complicated row level security. For a more powerful approach it might be useful to check the following link.
https://msdn.microsoft.com/en-us/library/dn765131.aspx
You could create the same tables with different schemas and assign user rights to different schemas. For example, instead of using dbo.Users you could have Accounting.Users and Warehouse.Users. Assign users in an accounting group to the Accouting schema. Or as suggested above those could be views within a schema that select data from underlying tables.

Why did PostgreSQL merge users and groups into roles?

From the PostgreSQL docs:
The concept of roles subsumes the concepts of "users" and "groups". In
PostgreSQL versions before 8.1, users and groups were distinct kinds
of entities, but now there are only roles. Any role can act as a user,
a group, or both.
Why did they make this change in 8.1?
Perhaps it's easier from the C coders point of view, with a single Role class (struct)?
More details:
CREATE USER is equivalent to CREATE ROLE except that CREATE USER gives the LOGIN permission to the user/role.
(I'm about to design a permission system for my webapp, hence I'm interested in this.)
The merge has many advantages and no disadvantages. For instance, you can now seamlessly convert a "user" to a "group" and vice versa by adding / removing the LOGIN privilege.
ALTER ROLE myrole LOGIN;
ALTER ROLE myrole NOLOGIN;
Or you can GRANT membership in any other login ("user") or non-login role ("group") to a role:
GRANT joe TO sue;
You can still:
CREATE USER james;
That's just a role with login privilege now. Or:
CREATE GROUP workers;
That's effectively the same as CREATE ROLE now.
The manual has it all.
I found this thread in the PostgreSQL-Hackers list, from June 6, 2003, that in the end suggests that users and groups and roles be consolidated. (Thanks Craig Ringer for suggesting that I check the pgsql-hackers list archives.)
Here are some benefits mentioned (those that I found).
allow groups to have groups as members
the ACL code would be simplified
the GRANT/REVOKE syntax and the display format for ACL lists could be
simplified, since there'd be no need for a syntactic marker as to
whether a given name is a user or a group.
In some circumstances I could see it making sense to allow logging in
directly as a group/role/whatchacallit
This would also solve the problem that information_schema views will
show only owned objects
[makes it easier to] representing privileges granted to groups [since
you'd simply reuse the role related code?]
From the manual:
The SQL standard defines the concepts of users and roles, but it
regards them as distinct concepts and leaves all commands defining
users to be specified by each database implementation. In PostgreSQL
we have chosen to unify users and roles into a single kind of entity.
Roles therefore have many more optional attributes than they do in the
standard.
Having a distinction between users and groups doesn't gain you anything.
AFAIK the motivation for changing it was to simplify uses like:
One user masquerading as another, eg a superuser simulating a reduced permissions user. With unified roles this becomes just another change of current role, no different to changing primary group.
Groups that are members of other groups to implement granular access permissions.
If you want the details, though, you're best off checking out the archives of the pgsql-hackers list for the period, and the git history (converted from CVS).