Exclusive User ownership on sql server tables - sql-server

Requirement: User who created tables in a particular schema, should own the tables, other users who got access to that schema should not able to perform any action on that table(including read).
Example:
Tables created by ‘User1’ in ‘Schema1’ should be exclusive to the User1 only with (SELECT, CREATE, UPDATE and DELETE)
Other Users who got access to ‘Schema1’, should not able to perform any actions on the tables created by ‘User1’
This requirement is expected to be available for users who have access to the 'schema1', so the tables they create is accessible only for them and not for other users.

For the sake of the discussion let's CREATE new LOGIN, new SCHEMA, and new USER.
use master
GO
CREATE LOGIN SO_Login WITH PASSWORD = 'Dont1Use2This3In4Production'
GO
Use AdventureWorks2019
GO
CREATE SCHEMA SO_Schema
GO
CREATE USER SO_User FOR LOGIN SO_Login;
GO
In theory, you could get what you are looking for, by simply have a rule which allows CREATE TABLE on specific schema. Something like: GRANT CREATE TABLE ON SCHEMA::SO_Schema TO public;
In this case we could give everyone the option to CREATE TABLE on the schema and use simple DDL trigger on CREATE TABLE in order to add permissions like SELECT,DELETE,INSERT,UPDATE for the user that created the table.
unfortunately, GRANT CREATE TABLE ON SCHEMA is not supported.
To CREATE TABLE you Required to have CREATE TABLE permission in the database and ALTER permission on the SCHEMA in which the table is being created.
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15#permissions-1
This makes the task more complex and probably not recommended in most cases since you will need to provide more permissions than what you really want the USER to have...
If you still want to get this work (against the recommendation) then you will need to GRANT ALTER ON SCHEMA and GRANT CREATE TABLE on database to all - all means "public"
use AdventureWorks2019
GO
GRANT ALTER ON SCHEMA::SO_Schema TO public;
GO
GRANT CREATE TABLE TO public;
GO
next, you will need to DENY the unwonted permission since the above will give all USERs a lot more power than you want to!
This can be done by CREATE DDL TRIGGER on the DATABASE for any DDL_DATABASE_LEVEL_EVENTS
https://learn.microsoft.com/en-us/sql/relational-databases/triggers/ddl-event-groups?view=sql-server-ver15
inside the TRIGGER you should check what was the event. If it was something else than CREATE_SCHEMA or the USER that executed the event should not CREATE SCHEMA then you ROLLBACK TRANSACTION;.
Note! Since you do not want to change the trigger each time a new USER need to CREATE TABLE and add the USER name to the hard coded list of users which can CREATE TABLE, it is best to CREATE new ROLE and simply add each USER you need to this ROLE
CREATE ROLE ModifyTable;
GO
In this case that you based on a ROLE like above ModifyTable, you can GRANT ALTER ON SCHEMA and GRANT CREATE TABLE only to the ROLE ModifyTable instead of to public
In addition, in the same TRIGGER if the USER is one of these that should be able to CREATE the table then you should GRAND him permission to INSERT, DELETE, UPDATE, SELECT on the table which he just created.
Remember that if you forget to DENY a permission from this USER or all the rest then you might have a security issue - which is why this is not recommended procedure.
Your best option is to re-0design the system so you will not need this exact recruitment. So... you can do it as I explained here, but it is not recommended for most cases.
A much better approach is NOT to permit USERs to CREATE TABLEs except for these you can trust with all tables. You should CREATE THE TABLEs for your users directly or using application which you control, and give them the permission to use the specific table which they need. ALTER SCHEMA is not recommended permission to give to simple users!
A user with ALTER permission on a schema can create procedures, synonyms, and views that are owned by the schema's owner. Those objects will have access (via ownership chaining) to information in other schemas owned by the schema's owner. When possible, you should avoid granting ALTER permission on a schema if the schema's owner also owns other schemas.
https://learn.microsoft.com/en-us/sql/t-sql/statements/grant-schema-permissions-transact-sql?view=sql-server-ver15

Related

How to create a schema in sqlcmd that is scoped to one specific user? Do I need to add explicit deny rules individually?

I am looking at docs and can't seem to figure out how to do this with a wildcard or blanket permission without doing individual deny statements
Assuming a real-world scenario, when you most probably will need:
Multiple users needing the same level of access;
Users being unable to change or drop objects, such as tables, in your database.
here is the approach you can use. You can create a role which will have the necessary permissions on a schema, so whatever objects will be placed into that schema in the future, the role will have access to them:
create role SchemaUser_X authorization dbo;
go
create schema Schema_X authorization dbo;
go
-- You can add or remove permissions here, as necessary
grant select, update, delete, insert, execute on schema::Schema_X to SchemaUser_X;
go
After that, you can add your users as role members:
create user User_X without login; -- Or by your preferred means
go
alter role SchemaUser_X add member User_X;
go
-- Repeat with as many users as need access to [Schema_X]
P.S. If you actually need to allow your users to manage objects within their corresponding schemas, such as creating tables, views, procedures, etc. then you can turn these roles into schema owners:
create role SchemaUser_X authorization dbo;
go
create schema Schema_X authorization SchemaUser_X;
go
-- Grants are unnecessary as the role has CONTROL permission on schema in this case
However, in most cases you wouldn't want that.

Revoke access from PostgreSQL User to see other tables

I have a PostgreSQL DB user "limited_user" and want to give SELECT permission on one table ONLY.
GRANT CONNECT ON DATABASE "db1" TO limited_user;
GRANT SELECT ON TABLE users to limited_user;
What happens is that when I try \dt , the user can see all the other tables in this db1, while he can perform SELECT operation to table "user" as I gave permission. How can I revoke access access to the user so that he can not see other tables and just one table?
You can't, at least not in any straightforward way that I am aware of.
Tables exist within the schema namespace, and schemas exist within the database. To give access to a user on a particular table means you must also give that user the USAGE permission on the schema to which the table belongs. USAGE does not grant permissions on the tables themselves, only the the schema in question. But table definitions are part of the schema, so USAGE does allow the user to see table names (and the columns too).
But if there are other tables in the same schema, the user will not be able to SELECT from those tables unless you also GRANT SELECT on those tables, even though they will be able to see that they exist.
This answer gives a pretty clear explanation of the permission system.
Edit to add:
One way to achieve a similar outcome would be like this (using psql):
sec_schema=# REVOKE ALL ON ALL TABLES IN SCHEMA sec_schema FROM restricted_user;
REVOKE
sec_schema=# REVOKE USAGE ON SCHEMA sec_schema FROM restricted_user;
REVOKE
sec_schema=# CREATE SCHEMA new_schema;
CREATE SCHEMA
sec_schema=# GRANT USAGE ON new_schema TO restricted_user;
GRANT
sec_schema=# CREATE VIEW new_schema.secret_view AS SELECT * from sec_schema.secret_table;
CREATE VIEW
sec_schema=# GRANT SELECT ON new_schema.secret_view TO restricted_user;
GRANT
This will remove all access to the schema sec_schema for user restricted_user, but then creates new_schema and new_schema.secret_view which is a cover view over sec_schema.secret_table. After the GRANT SELECT, the user will be able to read the data from table sec_schema.secret_table through the view, but they will not be able to see any objects in sec_schema.

recreate user with schema

Following code recreates a user:
-- Remove link to order schema
ALTER AUTHORIZATION ON SCHEMA::order TO dbo
-- Recreate order user without login
DROP USER order
CREATE USER order WITH DEFAULT_SCHEMA = order
-- Restore link to order schema
ALTER AUTHORIZATION ON SCHEMA::order TO order
My question is, why do we need to remove link to schema before dropping a user, and restore it back after user created?
The behavior of Schemas changed in SQL Server 2005. Schemas are no longer equivalent to database users; each schema is now a distinct namespace that exists independently of the database user who created it. In other words, a schema is simply a container of objects. A schema can be owned by any user, and its ownership is transferable.
https://msdn.microsoft.com/en-us/library/ms190387.aspx
http://basitaalishan.com/2014/05/29/the-database-principal-owns-a-schema-in-the-database-and-cannot-be-dropped/
Ok, just found why we need to temporary move the schema link to another owner before deleting a user.
It will return error if not doing so:
The database principal owns a schema in the database, and cannot be dropped.

Sql Server Schemas, one private area per person, but have read access to others

I have a requirement for a database that is effectively a "play" area for people creating stats data for themselves and shared with others.
I have a read only database full of core data. All users have read access.
I want a second "play" database where 'n' people can query the "core" database and create there own tables, Sp's etc. I want these users to have a schema each. I want everything they create to be added to their schema by default unless they specify it explicitly (ie [dbo]) in the script. I want them all to be able to collaborate and be able to read data (and look at sp's) from other users schema but not add objects or execute sps' in the others users schema.
These users use 2014 management studio to run these queries. They all authenticate using Integrated Security (windows).
Can this be done?
I tried setting default schema on a user but by default when they add a table it goes to [dbo] because the property grid in 2014MS defaults to [dbo] and you have to edit it. If they just enter "create table Table1" I want it to go into their schema
I tried making the user the owner of the schema. I tried setting public to have select access to these user schemas. But something is not right!
I would have thought this was a common setup where developers get their own schema within a single database. Or, is it always the case that separate DB's are used to achieve this? I am sure others would appreciate a short script that sets this up for a couple of users :)
SQL Server admin is not my main area, so any guidance would be appreciated
For a test user User1, you can create a schema UserSchema1 and do the following
I want a second "play" database where 'n' people can query the "core" database
you can make the user part of the db_datareader role like this
USE [CoreDatabase]
GO
exec sp_addrolemember db_datareader, 'User1'
I want everything they create to be added to their schema by default
Create the schema and add appropriate permissions
USE [PlayDatabase]
GO
CREATE SCHEMA [UserSchema1] AUTHORIZATION dbo;
GO
GRANT ALTER, DELETE, EXECUTE, INSERT, REFERENCES, SELECT, UPDATE, VIEW DEFINITION ON SCHEMA::UserSchema1 TO User1;
GRANT CREATE TABLE, CREATE PROCEDURE, CREATE FUNCTION, CREATE VIEW TO User1;
Make the schema default for the user
ALTER USER [User1] WITH DEFAULT_SCHEMA=[UserSchema1]
For more info refer this thread
https://dba.stackexchange.com/questions/21733/allow-user-to-do-anything-within-his-own-schema-but-not-create-or-drop-the-schem
I want them all to be able to collaborate and be able to read data (and look at sp's) from other users schema but not add objects or execute sps' in the others users schema.
Allow user to view definition of other user's objects and do SELECT's on play database
USE [PlayDatabase]
GO
GRANT VIEW Definition TO [User1]
GO
exec sp_addrolemember db_datareader, 'User1'

Setting up a user to my database in my SQL Server

I just finished creating a new user for my database in SQL Server. I had 4 tables I wanted to grant Insert, Update, Select and delete permissions. I did this manually in the Securables area of the new user.
Is there a better way to do this that to have to touch each object? if so, how?
Thanks,
rod.
One way is use schemas such that
tables belong to a schema (let's call it data, CREATE SCHEMA)
users belong to a role (CREATE ROLE, sp_addrolemember)
permissions are assigned to the role on the schema (GRANT INSERT ON schema::data to myRole)
Now, you can add new tables or change users without losing/creating permissions
If you want finely granular control over who can do what, I don't think there's a whole lot you can do - you're doing it just fine.
gbn's approach is quite nifty - another approach for "simple" setups (when you don't need a whole lot of different permissions) is to:
grant every user (or a role) the database role db_datareader - this allows read access
(SELECT) on all tables and views
grant every user (or a role) the database role db_datawriter - this allows write access (INSERT, UPDATE, DELETE) on all tables and views
If you also need to grant execution rights on stored procedures, there's unfortunately no predefined role to use. You can however create your own database role and then grant execute permissions to that role. The great thing is: this permission to execute stored procedures also applies to all future stored procedure you might create in your database!
To define your new role, use this:
CREATE ROLE db_executor
GRANT EXECUTE TO [db_executor]
and then you can just assign db_executor to those users who need to be able to execute stored procs and stored functions in your database.

Resources