SQL Server : permissions to allow disable/reenable FK constraint, but no other alter - sql

Are there permission settings that will allow a principal to disable/enable a foreign key constraint, but not allow other table alteration?
E.g.: from a 'dbo' principal:
create login ref_test with password = 'test1234'
create user ref_test
exec sp_addrolemember 'db_datareader', 'ref_test'
exec sp_addrolemember 'db_datawriter', 'ref_test'
create table A (ID int not null, constraint PK_A primary key (ID))
create table B (Aid int not null, constraint FK_Aid_AID foreign key (Aid) references A(ID))
From a ref_test login-connection:
insert A values (1)
insert B values (1)
Now, I need to be able to update the key in the FK relationship, like so:
-- will fail
ALTER TABLE B NOCHECK CONSTRAINT FK_Aid_AID
update A set ID = ID + 1
update B set AID = AID + 1
ALTER TABLE B WITH CHECK CHECK CONSTRAINT FK_Aid_AID
This fails with
Msg 1088, Level 16, State 13, Line ...
Cannot find the object "B" because it does not exist or you do not have permissions
If I add
GRANT ALTER on B to ref_test
It will work, but not without also enabling ALTER TABLE B DROP CONSTRAINT FK_Aid_AID, as well as enabling other DDL on the table--add/drop columns, other constraints--though not allowing the FK in question to be re-added--that requires an additional GRANT REFERENCES (ID) on A to ref_test.

No, there's no way to do this with SQL Server's permission scheme. To perform any particular ALTER TABLE statement you need ALTER permission, and that in turn allows you to perform any ALTER TABLE statement whatsoever, save those that require updating columns or referencing external types or columns (which require separate rights).
One general way of granting accounts permission to do things they wouldn't otherwise be able to do (and only those things) is to encapsulate them in stored procedures that execute under privileged accounts. So let's say you want to give an account the ability to disable or enable any constraint on any table, but not to do anything else DDL-related with those tables:
CREATE PROCEDURE nocheck_constraint(#table SYSNAME, #constraint SYSNAME)
WITH EXECUTE AS OWNER AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = REPLACE(REPLACE(
'ALTER TABLE $table NOCHECK CONSTRAINT $constraint;',
'$table', QUOTENAME(#table)),
'$constraint', QUOTENAME(#constraint))
;
PRINT #SQL;
EXEC(#SQL);
END;
GO
-- The following is necessary only for direct calls.
-- Note that ownership chaining will allow *any* stored procedure to call this one without
-- a separate permission check, which is a double-edged sword.
GRANT EXECUTE ON nocheck_constraint TO [unprivileged_account];
And similarly for check_constraint. Of course you can make this more fine-grained as you require.
I'm taking a potentially dangerous shortcut here by leveraging EXECUTE AS OWNER so I can do dynamic SQL without security restrictions. If you are not in full control of the database and all procedures created in it, this has some consequences for the security of not just the database, but the rest of the server as well. In that case, you may want to look into signing the procedure and using a proxy instead. Instead of hashing that all out here, I refer you to Erland Sommarskog's excellent writeup on the matter.

I have user(s) for which I wont to give permission in Management Studio to change extended properties for columns of table(s).
So when give ALTER permission on table for that user it can be seen Keys, Indexes, Constraint, even it can not be changed. So not to be seen there is DENY on SELECT in sys.check_constraint, sys.foreignkeys, sys.key_constraint ....
So maybe with ALTER ON tables and some combination of DENY and GRANT on sys.columns, sys.foreignkeys, sys.check_constraint....it is possible to allow a principal to disable/enable a foreign key constraint, but not allow other table alteration

Msg 1088, Level 16, State 13, Line ...
Cannot find the object "B" because it does not exist or you do not have permissions
if I do this with management studio, I notice next:
if I don't have SELECT permission on particular table it will be a problem, all ForeignKey will be disappear
If I don't have SELECT permission then in CheckExistingData on Creation or Enabling if it is yes it should be changed in No, and EnforceForeignKey Constraint can be changed from Yes to No, or opposite
So :
1. or SELECT permission on table (which is needed for CheckExistingDataOnCreatinon or Reanabling if it is set to Yes)
2. or CheckExistingDataOnCreation or Reanablig (creating again) set to No

Related

is there a specific query to find the trigger_owner and constraint_owner in postgressql?

for example :-
Trigger name can be derived from pg_trigger but that trigger could be created by some other user who has access and could have created the trigger.
Similar issues for constraint_name .
For table emp(
user_id varchar(20),
emp_name varchar(20),
emp_salary integer);
Suppose user1 creates this table and user2 creates trigger and constraint name.
So is there a way to know who created trigger and constraint name because in the pg_trigger table and information_schema.columns will show user1 as trigger_owner and table owner.
A trigger is not something that is associated with PostgreSQL's system of permissions, and therefore there is no need to record the creator/owner of a trigger. The same applies for constraints on a table. Procedures/functions require permissions so that a DBA can limit who calls/runs the procedure; a trigger is merely something that calls a procedure when a change is made to a table (and therefore essentially anyone with write access to the table should have access to fire the trigger).
While ownership is really only relevant when it comes to permissions, if you want to know the creator for auditing purposes, I would recommend that you use the %u flag in log_line_prefix and set log_statement = ddl or log_statement = all so that you can see which user created the trigger/constraint.

POSTGRES - Risk of dropping foreign data wrapper/schema

We had one of the devs create a foreign data wrapper with these commands:
CREATE SERVER serverName FOREIGN DATA WRAPPER postgres_fdw OPTIONS (xxxx);
CREATE USER MAPPING FOR user SERVER foreign_db OPTIONS (user 'xxxx', password 'xxxx');
CREATE SCHEMA foreign_db;
IMPORT FOREIGN SCHEMA public FROM SERVER serverName INTO foreign_db;
To drop this schema the suggestion was to run:
DROP SCHEMA if exists foreign_db cascade;
DROP USER mapping if exists for user server foreign_db;
DROP SERVER if exists serverName;
In the spec I see this for CASCADE:
Automatically drop objects (tables, functions, etc.) that are
contained in the schema, and in turn all objects that depend on those
objects
what concerns me is this line:
and in turn all objects that depend on those objects
My question is there a possibility of dropping anything outside of foreign_db schema and if yes, how can I check it?
Thank you.
It is possible that the command drops something outside the schema. Consider this:
create schema example;
create table example.my_table (id int);
create view public.my_view as select * from example.my_table;
If the schema is dropped with the cascade option, public.my_view will also be dropped. However, the behavior is logical and desirable.
You can check this executing these commands one by one:
begin;
drop schema example cascade;
rollback;
The schema will not be dropped and after drop... you should get something like this:
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table example.my_tabledrop cascades to view my_view
Alternatively, you can use the system catalog pg_depend, see this answer How to list tables affected by cascading delete.

Issue with truncating table WITH ALTER permissions

I have read here Permissions for truncating a table that you need to grant ALTER permissions to the user(s) for them to be able to truncate a table. However, I am still having issues truncating the table with the user(s) being granted this role.
Any ideas why this is?
PS. I myself as the owner of the table am able to truncate by the way. Just no one else with ALTER permissions.
The link you are referring to is applicable to MS SQL Server. The link in the comment by Leila is also for SQL Server.
For Oracle the users must have the DROP ANY TABLE system privilege.
This in turn may not be what you want, as this system privilege is too destructive.
Tom Kyte has a solution for your problem:
Sure, this is what stored procedures are all about.
To selectively give someone the abilitly to truncate a specific table,
or all of the tables owned by some schema, you would code:
create or replace procedure do_the_truncate as begin execute immediate
'truncate table T'; end;
or (any of the tables owned by some schema, or if that schema has the
drop any table priv ANY table)
create or replace procedure do_the_truncate( p_tname in varchar2 ) as
begin execute immediate 'truncate table ' || p_tname; end;
and then just grant execute on that procedure to any user that needs
to run that command. Since stored procedures run with the base privs
of the OWNER of the procedure, you do not need any powerful privs like
"drop any table" to truncate that table.
You can further enhance the do_the_truncate stored procedure to have a list of allowed tables to be truncated to tighten the security in your system

Restricting permission to drop column in SQL Server?

ALTER TABLE [dbo].[Client] ADD [Awesomness] [nvarchar](max)
ALTER TABLE [dbo].[Client] DROP COLUMN [Awesomness]
The second command I don't want to be successful, I don't want any DROP COLUMN to succeed. So I created a user for my database, just wondering how I can deny this user the permission to DROP COLUMN. I set up a trigger but that doesn't seem to take care of DROP COLUMN. Is there anyway I could restrict this?
CREATE TRIGGER [TR_DB_NO_DROPPING_OBJECTS_2]
on DATABASE
FOR
DROP_PROCEDURE,DROP_FUNCTION,DROP_VIEW,DROP_TABLE, DROP_DEFAULT,DROP_EXTENDED_PROPERTY
AS
BEGIN
IF --only two accounts allowed to drop stuff
suser_name() NOT IN('test' )
BEGIN
--raise an error, which goes to the error log
RAISERROR('Unauthorized use of drop object from inpermissible host.', 16, 1)
--prevent the drop
ROLLBACK
END
--if it got to here, it was the "right" user from the "right" machine (i hope)
END
The roles I've assigned my user.
use Hasan
go
EXEC sp_addrolemember N'db_datareader', N'TestUser'
go
use Hasan
go
EXEC sp_addrolemember N'db_datawriter', N'TestUser'
go
use Hasan
GO
GRANT EXECUTE TO [TestUser]
GO
use Hasan
GO
GRANT INSERT TO [TestUser]
GO
use Hasan
GO
GRANT SELECT TO [TestUser]
GO
use Hasan
GRANT ALTER TO [TestUser]
GO
use Hasan
GO
GRANT UPDATE TO [TestUser]
GO
use Hasan
GO
GRANT DELETE TO [TestUser]
GO
That would be an Alter_Table DDL event. See if that works for you.
Also, I am not sure if you have looked into roles. Granting dbwriter and dbreader allows CRUD operations but no changes to DDL.
https://msdn.microsoft.com/en-us/library/ms189121.aspx
EDIT:
This example does not check for a user but it works on my test table:
CREATE TRIGGER testtrig
ON Database
FOR alter_table
AS
Declare #Msg nvarchar(max) = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'))
If #Msg Like '%Drop Column ColumnA%'
Rollback
GO
There is probably a better way than parsing the message text like in my example, this was just a quick test.
Also remember this is just a safety to let the user know they should not drop this column. If they have DDL rights they can disable or delete the trigger.

Minimum set of permissions required for SQL Server database?

I am writing a program in java in which i have to validate whether the user has all the minimum permissions required for creating, altering and deleting a table, procedure.
By default, my SQL Server database has following set of privileges:
CREATE TABLE-
CREATE VIEW-
CREATE PROCEDURE-
CREATE FUNCTION-
CREATE RULE-
CREATE DEFAULT-
BACKUP DATABASE-
BACKUP LOG-
CREATE DATABASE-
CREATE TYPE-
CREATE ASSEMBLY-
CREATE XML SCHEMA COLLECTION-
CREATE SCHEMA-
CREATE SYNONYM
CREATE AGGREGATE
CREATE ROLE
CREATE MESSAGE TYPE
CREATE SERVICE-
CREATE CONTRACT-
CREATE REMOTE SERVICE BINDING-
CREATE ROUTE
CREATE QUEUE
CREATE SYMMETRIC KEY
CREATE ASYMMETRIC KEY
CREATE FULLTEXT CATALOG
CREATE CERTIFICATE
CREATE DATABASE DDL EVENT NOTIFICATION
CONNECT-
CONNECT REPLICATION
CHECKPOINT
SUBSCRIBE QUERY NOTIFICATIONS
AUTHENTICATE
SHOWPLAN
ALTER ANY USER
ALTER ANY ROLE
ALTER ANY APPLICATION ROLE
ALTER ANY SCHEMA-
ALTER ANY ASSEMBLY
ALTER ANY DATASPACE
ALTER ANY MESSAGE TYPE
ALTER ANY CONTRACT
ALTER ANY SERVICE
ALTER ANY REMOTE SERVICE BINDING
ALTER ANY ROUTE
ALTER ANY FULLTEXT CATALOG
ALTER ANY SYMMETRIC KEY
ALTER ANY ASYMMETRIC KEY
ALTER ANY CERTIFICATE
SELECT-
INSERT-
UPDATE-
DELETE-
REFERENCES-
EXECUTE-
ALTER ANY DATABASE DDL TRIGGER
ALTER ANY DATABASE EVENT NOTIFICATION
ALTER ANY DATABASE AUDIT
ALTER ANY DATABASE EVENT SESSION
KILL DATABASE CONNECTION
VIEW DATABASE STATE
VIEW DEFINITION
TAKE OWNERSHIP
ALTER-
CONTROL
However I am validating only for the below specific permissions:
CREATE TABLE
CREATE VIEW
CREATE PROCEDURE
CREATE FUNCTION
BACKUP DATABASE
CREATE TYPE
CREATE SCHEMA
CREATE SYNONYM
CREATE AGGREGATE
CREATE ROLE
CREATE MESSAGE TYPE
CONNECT
ALTER ANY ROLE
ALTER ANY APPLICATION ROLE
ALTER ANY SCHEMA
ALTER ANY MESSAGE TYPE
SELECT
INSERT
UPDATE
DELETE
REFERENCES
EXECUTE
VIEW DATABASE STATE
VIEW DEFINITION
ALTER
CONTROL
However, with this set of permissions, when I am executing any user defined data type (sp_addtype), it is failing showing user doesn't have permissions. Can someone please tell me what extra permissions from the first set of permissions I need to add in the 2nd set of permissions?
[sp_addtype]
Permissions
Requires membership in the db_owner or db_ddladmin fixed database role.
You can look into procedure [sp_addtype]:
if is_member('db_owner')=0 and is_member('db_ddladmin')=0
begin
raiserror(15247, -1, -1)
return (1)
end