How to Revoke SELECT Permission for system_views To public - sql-server

I have the following T-SQL to display all the permissions granted to principals on my SQL server 2005:
select dp.NAME AS principal_name, --1
dp.type_desc AS principal_type_desc, --2
o.NAME AS object_name, --3
p.permission_name, --4
p.state_desc AS permission_state_desc --5
from sys.database_permissions p
left OUTER JOIN sys.all_objects o
on p.major_id = o.OBJECT_ID
inner JOIN sys.database_principals dp
on p.grantee_principal_id = dp.principal_id
order by principal_name, object_name
The result displays public with SELECT granted:
1 2 3 4 5
...
public DATABASE_ROLE system_views SELECT GRANT
....
I think object_name system_views is for all the views in my database Views|system_views folder. I tried the following T-SQL (just to see if it works by GRANT again):
GRANT SELECT ON system_views TO public
I got error "Cannot find the object 'system_views', because it does not exist or you don't have permission". I do connect the SQL server as sa.
My question is how to revoke SELECT permission on system_views for public (user or principal?) and roll permission back if I have to. The second question is if the revoke on system_views for public have any side-effect for other users?

There's no reason to revoke rights to view the system views. Users can only see the objects that they already have access to, so they already know those objects exist.
If you want to grant a user the right to see all objects in the database then grant them view definition on the schema or the database.

select * from sys.system_views
Does public have VIEW DEFINITION on any of these?
I would highly recommend against mucking about with any of this.
You could just
DENY VIEW DEFINITION ON SCHEMA::DBO TO PUBLIC

public is a "special" role. Don't mess with it.
Every user is a member of public by default, for example.
Metadata visibility actually determines what a user sees. So even if someone does SELECT * FROM sys.columns, they will see only the columns for objects they have rights on. No other rights = only info on the columns for system views.
You're likely to break stuff if you do this, especially in SSMS or direct access clients (Access, Excel etc)

Related

How to find which Database Roles are associated with a given User?

In SSMS I have a User X and there are Y, Z and P Database Roles available, how may I check what roles are added to a user X?
What have I tried:
In SSMS right click on database -> properties -> Permissions and see Explicit tab for a user X. I can see Permissions not association between role and the user. The same is for role I'm interested in, I see only permissions for role.
EDIT: Regarding GUI solution, I have no Properties option available for Users nor Roles.
You can use the sys.database_principals object to find this out:
SELECT u.[name] AS [UserName],
r.[name] AS RoleName
FROM sys.database_principals u
JOIN sys.database_role_members drm ON u.principal_id = drm.member_principal_id
JOIN sys.database_principals r ON drm.role_principal_id = r.principal_id
WHERE u.[type] IN ('S','U') --SQL User or Windows User
AND u.[name] = N'X';
Through the GUI:
Open the database that you want to check, open Security folder, open Users folder. Here you have a list of defined users for this database.
Right click a user -> properties -> Membership. Here you see the defined roles for this database (custom roles also end up in this list). The user has/is a part of the role if it has an X/mark infront of it.
Through script:
SELECT DP1.name AS DatabaseRoleName,
isnull (DP2.name, 'No members') AS DatabaseUserName
FROM sys.database_role_members AS DRM
RIGHT OUTER JOIN sys.database_principals AS DP1
ON DRM.role_principal_id = DP1.principal_id
LEFT OUTER JOIN sys.database_principals AS DP2
ON DRM.member_principal_id = DP2.principal_id
WHERE DP1.type = 'R'
--AND DP2.name = 'YourUserName'
ORDER BY DP1.name;
Which lists all roles and the users which are a member of it. (Script is from msdn link).
This script goes from roles to users. For a specific user fill in the commented parameter. Or just use the script provided by Larnu.
I do it this way:
select user_name(role_principal_id)
from sys.database_role_members
where member_principal_id = user_id('your_user');

SQL Server domain name and user name formatting

I am executing a SQL script in SQL Server Management Studio 2018. In my script I need to specify a user (including the domain - unsure if I need the server name).
So I have created a user sam, set the user type to SQL user without login and set the users role to db_datareader and db_datawriter.
I then execute my script but it gives me the error: User or role 'MHT.sam' does not exist in this database.
But I am almost certain I have added this user to the database (see my images below to double check). Is my user and domain name format correct? What do you think I am doing wrong?
Here's my domain and server:
The error is pretty obvious.
In your screen shot in the object explorer you have a user called SAM, but for sp_AddRoleMember you are using MHT.SAM user.
Your sp_addrolemember should also have only Sam something like...
Exec sp_addrolemember N'RunStoredProc' , N'Sam'
GO
Also to double check what your user type is what login it is mapped to and what really is going on, use the following query.
SELECT
d.name AS User_Name
, d.type_desc AS User_Type
, d.default_schema_name AS User_default_schema_name
, d.create_date AS User_Created_Date
, s.name AS Login_name
, s.type_desc AS Login_LoginType
, s.is_disabled AS Login_is_disabled
, s.create_date AS Login_create_date
, s.default_database_name AS Login_default_database_name
, s.default_language_name AS Login_default_language_name
FROM sys.server_principals s
INNER JOIN sys.database_principals d on s.sid = d.sid
WHERE d.name = 'Sam'

SQL Server Management Studio, Beginner

So, I have this question:
Use the following query to determine the principle_id values for suzie and jimmy.
select *
from sys.database_principals
where name in ('suzie','jimmy')
Using the principle_id values obtained from the query above; write a SELECT query using the
sys.database_permissions table that lists ALL permissions that have been granted to suzie and jimmy.
Principal id's I got were "5 & 6"
Then I used:
SELECT*
FROM sys.database_permissions
WHERE grantee_principal_id in ('5','6')
Now the question is we're asked now to use the OBJECT_NAME function in your query to show the view names instead of just their
major_id values. I don't quite understand how to use the OBJECT_NAME function, I have been playing around and can't get it. Any hints or help would be greatly appreciated. Thanks!
Are you looking for something like this?
grator_principal_id will return all objects where these principal gave the grant and grantee_Prinicipal_id return all objects where Suzie and Jimmy were granted Details here
SELECT *
,OBJECT_NAME(major_id) AS TheObject
FROM sys.database_permissions
WHERE grantor_principal_id in (select principal_id
from sys.database_principals
where name in ('suzie','jimmy'))

SQL Server sys.credentials Permissions

According to the documentation the user should have either VIEW ANY DEFINITION or ALTER ANY CREDENTIAL to view the credentials. The issue is when I grant this permission, the user can see all the credentials. Is there a way to limit the user can view only one credential in SQL Server 2014?
You create a new view object that looks at the sys.credentials table based on the current user login, e.g.
CREATE VIEW dbo.GetAllowedCredentials
AS
SELECT c.credential_id,
c.name,
c.credential_identity,
c.create_date,
c.modify_date,
c.target_type,
c.target_id
FROM sys.credentials AS c
INNER JOIN sys.server_principals AS sp ON sp.credential_id = c.credential_id
WHERE sp.name = ORIGINAL_LOGIN();
You can apply permissions to this view as required.

How To Query for Specific User Access Rights

I have an old database that I am inheriting. The access rights are not clearly defined anywhere and I'm looking for a quick way to get them for everyone. Let's say I have a user in my database that does not belong to any membership roles. However, they have been given access to do specific things to specific tables. For example, they can run select queries on table X and run update queries on table Y. I know I can find out what they have by going to the properties for each user. I would imagine, however, that there has to be a system table somewhere that has all of this defined in it and makes it easily queryable. What would this query look like.
FYI: I am working with SQL Server 2005
Update: Is there also a way to do this for all databases on the server?
Take a look at the Security Catalog Views, then check out MrDenny's answer here which gives a query to list a user's rights. I reproduce it here (tidied up to my liking)..
SELECT [Schema] = sys.schemas.name
, [Object] = sys.objects.name
, username = sys.database_principals.name
, permissions_type = sys.database_permissions.type
, permission_name = sys.database_permissions.permission_name
, permission_state = sys.database_permissions.state
, state_desc = sys.database_permissions.state_desc
, permissionsql = state_desc + ' ' + permission_name
+ ' on ['+ sys.schemas.name + '].[' + sys.objects.name
+ '] to [' + sys.database_principals.name + ']'
COLLATE LATIN1_General_CI_AS
FROM sys.database_permissions
INNER JOIN sys.objects ON sys.database_permissions.major_id = sys.objects.object_id
INNER JOIN sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
INNER JOIN sys.database_principals ON sys.database_permissions.grantee_principal_id = sys.database_principals.principal_id
ORDER BY 1, 2, 3, 5
Things are a bit trickier actually. The effective permissions are a combination of internal database permissions (queryable as Denny's query showed above by doza) and windows group membership. Th later unfortunately is stored outside SQL, in the AD schema so you can't realy query it.
So if your goal is to display 'Access to the table X is given to domain\someuser and domain\somegroup and denied to domain\someothergroup' then you can use the catalog metadata and query it, as showed in doza's post.
However if your goal is to answer 'Does user domain\someuser have access to table X?' you can't get the answer from the query above. That's right, despite the fact that you see a record saying the domain\someuser is granted access, you cannot answer if it has effective access. Remember that a single deny trumps all grants, and if domain\user is member of domain\someothergroup group then domain\someuser is effectively denied access.
To answer the later question you must use a different mechanism, namely you have to impersonate the user at SQL level and check the permission via HAS_PERM_BY_NAME:
EXECUTE AS USER = 'domain\someuser';
SELECT HAS_PERMS_BY_NAME('X','TABLE','SELECT');
REVERT;
Is worth noting that the first question can be answered by anyone with view privileges on the security catalogs, while the later requires impersonate permission, a much more powerful privilege.

Resources