We have a table and multiple users access that table. However we would like to hide records in that table from a user group lets say GroupA. So that they don't see any records in their database except the ones that were created by them.
GroupA users should also have an option to add new records and edit their own record.
However, all other users (except groupA) should be able to see all records in the table.
We have SQL Server 2012.
Thanks.
You could create a view on the table for GroupA restricting records with appropriate criteria and grant SELECT to GroupA on view.
This is called row level security.
One common way is to allow access to the table only via a view.
(You can also write into a view).
The view must contain a WHERE statement which selects the rows the user is allowed to see.
BTW, be sure to use ORIGINAL_LOGIN when you reference to the current user.
Related
I am in the process of creating an audit plan using ERD, going off the below image you can see that there's a permissions table with four FK columns referring to the other four tables PK column. I am just confused as to how the IDs will relate to the other tables and how will it show up correctly in the permissions table?
For the Users table, I imported the data from 'master.sys.server_principals.
For the Instance table, I imported the data by using ##SERVERNAME.
For the Databases table, I imported the data from master.sys.databases.
For the Object Types table, I imported the data from master.sys.objects.
Now, I am currently on the permissions table and stuck at this point because I am wondering how will the IDs match from the four other tables (mentioned above and shown in the image link below) to this permissions table. I know I need to query from master.sys.database_permissions to get the information for both columns 'Permissions_Permission_Name' and 'Permissions_Object_Name' but it's just the other four ID columns which I am confused about...(you can ignore the column Permissions_ID)
I'm going to use the Answer field, because there is no space in the Comment editor. This answer is an answer to only part your question, two of the four tables (Databases and Users) I can relate to system tables.
First and foremost: when filling in Id's, you would generate the other table records first, keep the Identity Id's generated, and finally create a new Permission record and fillin the correct indexes there, in each Id field. That counts for any such change when a table contains indexes to other tables. Suppose you know.
Issue is, your structure differs from the system tables. You will need more "permission" records than master.sys.database_permissions, because MsSQL registers these as permissions per principal (role) not permissions per user.
I solved two of the four:
The user is connected to a principal role via master.sys.database_role_members. The Id of the user role can be found in your source as master.sys.database_permissions.grantee_principal_id and the corresponding users that have this principal_id are listed in master.sys.database_role_members.
Your permission a database (ONE database) is defined in your Permission record. The database name in this database record should map to a database on your server. In that database, you will find database_permissions.sys.server_principals. users that have the permissions are (again) found in master.sys.database_role_members.
I'm not sure what you intend to do with the other 2 tables, Instances and Object Types.
Refer ms-docs about the subject at https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-permissions-transact-sql?view=sql-server-ver15
Background:
I have users connect to Apache Drill with Kerberos authentication to read from a Parquet file so basically a single table with multiple columns. Some of the columns in that file are known to be sensitive and only certain users can see them. Apart from the data table Drill has access to another table with information who has access to sensitive data (2 columns there: userId, sensitiveDataAccess). To emphasize, users can see all rows in the data table, but only those who have access to sensitve data can see the sensitive columns.
This can be achieved using impersonation.
https://drill.apache.org/docs/configuring-user-impersonation/
The solution is to create a view joining the data table with a row from the security table containing information about access to sensitive data for the logged in user and then using conditions in the SELECT clause to nullify sensitive columns if a user does not have access to them.
SELECT
hc.name,
CASE WHEN sec.`sensitiveDataAccess`=TRUE THEN hc.`salary` ELSE null END AS salary, --example of a sensitive column
FROM dfs.`/data/headcount.parquet` hc
JOIN (SELECT * FROM dfs.`/data/security.parquet` WHERE userId=session_user) sec
ON sec.userId=session_user;
You might need to enable cartesian joins in Drill to make it work or add a dummy column with zeroes in both tables and then add the below to the join condition as a workaround:
AND hc.JoinHack=sec.JoinHack
I have a column called Note, roleName and there are two roles, admin and engineer.
The engineer updates the notes and saves it , at the same time when admin logs in and modifies the same record (notes), he should be able to do it. How can I achieve this using case sql?
If two users update the same field in the same table, then the user which updates last, will win. If you are trying to do something like Google Docs, where many users can update the same data, that is going to be more than just a update to a table.
In this question: How do I use row-level permissions in BigQuery? it describes how to use an authorized view to grant access to only a portion of a table. But I'd like to give different users access to different rows. Does this mean I need to create separate views for each user? Is there an easier way?
Happily, if you want to give different users access to different rows in your table, you don't need to create separate views for each one. You have a couple of options.
These options all make use of the SESSION_USER() function in BigQuery, which returns the e-mail address of the currently running user. For example, if I run:
SELECT SESSION_USER()
I get back tigani#google.com.
The simplest option, then, for displaying different rows to different users, is to add another column to your table that is the user who is allowed to see the row. For example, the schema: {customer:string, id:integer} would become {customer:string, id:integer, allowed_viewer: string}. Then you can define a view:
#standardSQL
SELECT customer, id
FROM private.customers
WHERE allowed_viewer = SESSION_USER()
(note, don't forget to authorize the view as described here).
Then I'd be able to see only the fields where tigani#google.com was the value in the allowed_viewer column.
This approach has its own drawbacks, however; You can only grant access to a single user at a time. One option would be to make the allowed_viewer column a repeated field; this would let you provide a list of users for each row.
However, this is still pretty restrictive, and requires a lot of bookkeeping about which users should have access to which row. Chances are, what you'd really like to do is specify a group. So your schema would look like: {customer:string, id:integer, allowed_group: string}, and anyone in the allowed_group would be able to see your table.
You can make this work by having another table that has your group mappings. That table would look like: {group:string, user_name:string}. The rows might look like:
{engineers, tigani#google.com}
{engineers, some_engineer#google.com}
{administrators, some_admin#google.com}
{sales, some_salesperson#google.com}
...
Let's call this table private.access_control. Then we can change our view definition:
#standardSQL
SELECT c.customer, c.id
FROM private.customers c
INNER JOIN (
SELECT group
FROM private.access_control
WHERE SESSION_USER() = user_name) g
ON c.allowed_group = g.group
(note you will want to make sure that there are no duplicates in private.access_control, otherwise it could records to repeat in the results).
In this way, you can manage the groups in the private.access_control separately from the data table (private.customers).
There is still one piece missing that you might want; the ability for groups to contain other groups. You can get this by doing a more complex join to expand the groups in the access control table (you might want to consider doing this only once and saving the results, to save the work each time the main table is queried).
In our multi-user Access environment, sometimes it is necessary to perform different actions on a group of records. In the Orders table, for example, a user may want to delete a group of orders, or to print out a group of records, etc. To accomplish this, in the Orders table, I created a boolean field called aSelect (the "a" is to avoid the "Select" SQL reserved keyword). On the Orders form, users can check off the orders which they want to process by clicking the checkbox for the aSelect field and then click "print", "delete", or whatever other operation. The code behind the form then says to process the operation on all Orders WHERE ASELECT=TRUE
The problem is that, (while it hasn't happened yet), the aSelect checkbox is bound to the underlying field in the table, and two users can change aSelect at the same time. So, suppose user A selects two records to delete, but before he hits the delete button, another user attempting to print a 100 records selects 100 records. The result will be that all 100 records will be deleted--not the intended result.
Any solutions or alternatives? This scenario plays out numerous times throughout the database. The Orders table is just one example.
Thanks,
Create a table with a username/userid column and an OrderID column.
When the user makes a selection, add a record to this table with the OrderID and username, then when running your query just join this selection table or use an IN() clause and filter by username.
Voila - user specific selections, which could be improved/expanded upon but this is my basic offering.