script to show all the permissions for a table
-
29-09-2020 - |
Question
inside my database I have a procedure called spGen2_tblIE_SchedProcess_Update.
when I run this script
select * from sys.objects
where name = 'spGen2_tblIE_SchedProcess_Update'
Inside the same database I have a table called tblIE_Step
when I run the following script
select * from sys.objects
where name = 'tblIE_Step'
then I want to see all the permissions of the objects.
when I check my stored procedure I run this script:
select 'Proc' = SCHEMA_NAME(p.schema_id)+'.'+p.name
, 'Type' = per.state_desc, 'Permission' = per.permission_name
, 'Login' = pri.name, 'Type' = pri.type_desc
, *
From sys.objects as p
left join sys.database_permissions as per on p.object_id = per.major_id
left join sys.database_principals as pri on per.grantee_principal_id = pri.principal_id
where p.object_id = 87671360
and I get the permissions:
But when I run the same for my table, I don't get anything:
select 'Proc' = SCHEMA_NAME(p.schema_id)+'.'+p.name
, 'Type' = per.state_desc
, 'Permission' = per.permission_name
, 'Login' = pri.name, 'Type' = pri.type_desc
, *
From sys.objects as p
left join sys.database_permissions as per on p.object_id = per.major_id
left join sys.database_principals as pri on per.grantee_principal_id = pri.principal_id
where p.object_id = 389576426
I know there are logins and groups that belong to roles that are have db_reader and db_writer permissions. However, they are not showing here.
How can I change my script so that it would show me all the permissions for this table?
Solution
I've got a couple of stored procedures you can use to display all of the permissions for a given database. Either for a single user/principal or for all of them. sp_dbpermissions and sp_srvpermissions.
The output for sp_dbpermissions (sp_srvpermissions is the same at a server level) looks like this
Off the page are revoke/grant/deny commands as appropriate.
FYI the example I have here was run using 'ALL' for the database parameter so it's displaying the output for all of the databases not just one.
I primarily intended them as research tools so you will find parameters that let you search out permissions directly applied to a given object (similar to your query above) or members of a given role (and the permissions for that role) etc.
Note: Minion also has an enterprise edition that does a lot of detailed data collection on permissions that might very well give you what you want. It is however a paid program. (If you can talk your management into the expense it's probably worth it)
OTHER TIPS
I found a good script to see the permissions on a database object.
SELECT
(
dp.state_desc + ' ' +
dp.permission_name collate latin1_general_cs_as +
' ON ' + '[' + s.name + ']' + '.' + '[' + o.name + ']' +
' TO ' + '[' + dpr.name + ']'
) AS GRANT_STMT
FROM sys.database_permissions AS dp
INNER JOIN sys.objects AS o ON dp.major_id=o.object_id
INNER JOIN sys.schemas AS s ON o.schema_id = s.schema_id
INNER JOIN sys.database_principals AS dpr ON dp.grantee_principal_id=dpr.principal_id
WHERE 1=1
AND o.name IN ('YOUR TABLE NAME') -- Uncomment to filter to specific object(s)
-- AND dp.permission_name='EXECUTE' -- Uncomment to filter to just the EXECUTEs
ORDER BY dpr.name
the script above works for a database object. however, when I add permissions on the schema where the db object is, the above script does not pick that up, for example:
grant delete on schema::dbo to [db_webUser]
GO
so for that case I found this script here that caters for that as well:
------------------------------------------------------------------------------------------------------------------
-- http://schottsql.blogspot.co.uk/2011/02/quickly-script-permissions-in-sql-2005.html
------------------------------------------------------------------------------------------------------------------
SELECT
state_desc + ' ' + permission_name +
' on ['+ ss.name + '].[' + so.name + ']
to [' + sdpr.name + ']'
COLLATE LATIN1_General_CI_AS as [Permissions T-SQL]
FROM SYS.DATABASE_PERMISSIONS AS sdp
JOIN sys.objects AS so
ON sdp.major_id = so.OBJECT_ID
JOIN SYS.SCHEMAS AS ss
ON so.SCHEMA_ID = ss.SCHEMA_ID
JOIN SYS.DATABASE_PRINCIPALS AS sdpr
ON sdp.grantee_principal_id = sdpr.principal_id
where 1=1
AND so.name = 'ItemStock'
UNION
SELECT
state_desc + ' ' + permission_name +
' on Schema::['+ ss.name + ']
to [' + sdpr.name + ']'
COLLATE LATIN1_General_CI_AS as [Permissions T-SQL]
FROM SYS.DATABASE_PERMISSIONS AS sdp
JOIN SYS.SCHEMAS AS ss
ON sdp.major_id = ss.SCHEMA_ID
AND sdp.class_desc = 'Schema'
JOIN SYS.DATABASE_PRINCIPALS AS sdpr
ON sdp.grantee_principal_id = sdpr.principal_id
where 1=1
order by [Permissions T-SQL]
GO
when I run the script above I get the following result, which includes the permission on the schema that reflects on my table.
The whole point of roles like the db_datareader
role is that you don't have to explicitly define read permissions for every person in that role for every object. So, you won't find a row in there for every user in the role. This is not a query, but you should essentially do this:
- Get all the users who have been explicitly granted access to that table, and for which a DENY/REVOKE does not exist.
- Get all the users who are members of any of the roles that implicitly grant read access to the given object (but again also check for explicit DENY/REVOKE).
Pseudo code (I'll update with real examples when I have time):
-- is user in role(s)? If so:
-- does role have exec on procedure - include them
-- does role have select on base table - include them
-- does role have DENY/REVOKE on procedure - exclude them
-- does role have DENY/REVOKE on table - exclude them
-- is user not in role(s)? Then:
-- does user have exec on procedure - include them
-- does user have select on base table - include them
-- does user have DENY/REVOKE on procedure - exclude them
-- does user have DENY/REVOKE on table - exclude them