TL;DR - Users automatically get added to db_owner group when created by script for some reason. But I can't remove them with a script.
So I have made a script to add new Windows-users to my database but for some reason they automatically get added to the db_owner group by default. The owner on the server is 'sa' so there is an owner set already on the server.
This is what happens when I add a new user with the following script:
CREATE LOGIN [Windows\user1] FROM WINDOWS WITH DEFAULT_DATABASE=[master], DEFAULT_LANGUAGE=[us_english]
GO
USE [dbName]
GO
IF NOT EXISTS (SELECT [name] FROM [sys].[database_principals] WHERE [name] = N'Windows\user1')
BEGIN
CREATE USER [Windows\user1] FOR LOGIN [Windows\user1]
END
EXECUTE sp_addrolemember 'Admin', 'Windows\user1'
GO
EXECUTE sp_addrolemember 'db_datareader', 'Windows\user1'
GO
EXECUTE sp_addrolemember 'db_datawriter', 'Windows\user1'
GO
But when I run the following code it says "1 row affected". But the user is still in the db_owner group.
ALTER ROLE [db_owner] DROP MEMBER [Windows\user1]
The only way I can remove it right now is using the UI in SSMS to go to the properties of the user and un-check it. What are some ways to fix either of the issues?
Apparently this wasn't correct. They don't even get removed this way...
Update(1):
I've managed to narrow it down to the fact that it does seem to have something to do with the custom role "Admin" - when a user is added to this role it automatically gets added to db_owner when running the following script.
EXECUTE sp_addrolemember 'Admin', 'Windows\user1'
Still haven't managed to figure out why.
Prediction: if you run the following query, then the result will be 1:
select count(*)
from sys.database_role_members rm
join sys.database_principals rp on rp.principal_id = rm.role_principal_id
join sys.database_principals mp on mp.principal_id = rm.member_principal_id
where rp.name = 'db_owner'
and mp.name = 'Admin';
If that is the case (and I am confident that it is), then the Admin role is a member of the db_owner role. So all members of admin are members of db_owner.
Then user1 is given membership in the admin role. We now form a syllogism:
All admins are db_owners.
user1 is an admin.
Therefore user1 is a db_owner.
Attempting to remove user1 from the db_owner role has no effect, because they are not a direct member of the db_owner role. They are a member of the admin role, which in turn is a member of the db_owner role.
If you want to remove their db_owner membership, you must do so by removing them from the admin role.
Related
I'm having an issue giving a single user the ability to perform
select * from msdb..sysmail_profile
I get the following error:
Msg 229, Level 14, State 5, Line 1
The SELECT permission was denied on the object 'sysmail_profile', database 'msdb', schema 'dbo'
I've tried to grant permissions by using:
use msdb;
grant select on msdb.dbo.sysmail_profile to [My User];
but still no avail. However, if I do the exact same grant permission command for [Public], then the user is able to perform the needed select statement, but I don't want [Public] to have access to select from that table.
I have not found any Deny's anywhere for this user, yet I am still unable to give this single user SELECT permissions. Any thoughts?
I think your context is not switched. Try with EXECUTE AS and see if the issue still persists. For me, the below code worked successfully without issues.
use master
go
CREATE LOGIN TestLogin with password = 'YOURSTRONGPASSWORD'
GO
use msdb
go
CREATE USER TestLogin for login testlogin
GO
grant select on msdb.dbo.sysmail_profile to [testlogin]
GO
EXECUTE AS user = 'Testlogin'
go
SELECT * FROM msdb.dbo.sysmail_profile
go
Revert
go
make sure in security > logins > [myuser]> user mapping > check msdb
(if the user still does not have access try to revoke public server role because I think the default in public server role for msdb is denied)
use msdb;
REVOKE select on msdb.dbo.sysmail_profile to public;
I'm gIven the problem:
Write a script that creates a user-defined role named VendorMaintenance in the AP database. Give update permissions to that role on the Vendors table and Select permission on the Invoice and InvoiceLineItems table. Assign the VendorMaintenance role to dbMaster.
I've looked through my textbook and came up with this incorrect solution.
USE AP
GO
CREATE SERVER ROLE VendorMaintenance
GO
GRANT UPDATE
ON Vendors
TO VendorMaintenance
GO
GRANT SELECT
ON Invoices
TO VendorMaintenance
GO
GRANT SELECT
ON InvoiceLineItems
TO VendorMaintenance
GO
ALTER SERVER ROLE VendorMaintenance ADD MEMBER dbMaster
GO
It says that VendorMaintenance isn't a user, and its not. but I need to grant these permissions to the role and then assign users to that role. Also is there a better way to write this?
For a user-defined database role, the syntax is as below. The role will be created in the current database context.
USE AP;
GO
CREATE ROLE VendorMaintenance;
GO
CREATE SERVER ROLE creates a user-defined server role, which is used to grant server-scoped permissions rather than permissions on database-scoped objects.
I have a tableA that disallow userA to update it. (userA is a DB user)
DENY UPDATE ON tableA TO userA;
When I login with Window Authentication, I update tableA with below query.
[Query]:
EXECUTE AS USER = 'userA';
GO
update tableA set colA='0001' where id=1;
GO
REVERT;
[Message]:
The UPDATE permission was denied on the object
'tableA', database 'DW', schema 'dbo'.
====> This is my expected result.
However, when I changed to login as 'userA' with SQL Server Authentication.
[Query]:
update tableA set colA='0001' where id=1
====> It allowed to update! It is supposed to block from updating, right? May I know why it does not block it? Anything I have missed out?
This may happen if the login userA is a member of the sysadmin server role.
To get the actual behavior of this login, you should impersonate the login instead of the user:
EXECUTE AS LOGIN='userA'
When you impersonate the user, only the rights explicitly granted to the user (in the current database) are considered. When you impersonate the login, also the server-level rights are considered.
If a login is a member of the sysadmin server role, the permissions (including any explicit DENY) are not verified anymore. According to https://learn.microsoft.com/en-us/sql/t-sql/statements/deny-transact-sql, "DENY does not apply to object owners or members of the sysadmin fixed server role".
Running a local instance of SQL Server 2012.
I have created a custom role:
CREATE ROLE [my_user] AUTHORIZATION [dbo]
For all my users (local Windows users and SQL users), I have specified this role for my database (under the User Mappings setting). Thus, the following query should return 1:
SELECT IS_ROLEMEMBER('my_user')
For my Windows-authenticated users it does indeed return 1, but as soon as I'm logged on as an SQL user, it returns 0. I have triple-checked that the SQL user does indeed have this role. What am I missing here?
Update
Performed some more testing. This certainly is weird behavior. I performed these steps:
On my local SQL Server I created a database test with user sa. Role my_user added.
Logged on as sa in the Management Studio and added MYDOMAIN\MyUser to this role.
Re-logged on with Windows Authentication and executed IS_ROLEMEMBER('my_user'). Returns 0.
Tried the query using both sa (specifying the username) and the Windows user. Same problem.
Tried restarting the SQL Server, just in case.
This makes no sense! If I right-click the role I can see that my Windows user is indeed a member of it. The IS_ROLEMEMBER function is flawed! When I run the following query, it shows that my user is indeed a member of the database role:
SELECT
USER_NAME(memberuid), USER_NAME(groupuid)
FROM
sys.sysmembers
WHERE
USER_NAME(groupuid) = 'my_user'
This also shows my membership:
select r.name as role_name, m.name as member_name from sys.database_role_members rm
inner join sys.database_principals r on rm.role_principal_id = r.principal_id
inner join sys.database_principals m on rm.member_principal_id = m.principal_id
Some additional information:
I'm on a domain, but currently disconnected. I have seen this problem when connected too though.
Running Windows 8.1 64-bit.
Update 2
If I explicitly specify the principal as some have suggested, I get this error (executing as sa):
SELECT IS_ROLEMEMBER('my_user', 'MYDOMAIN\UserX')
Msg 15404, Level 16, State 19, Line 1
Could not obtain information about Windows NT group/user 'MYDOMAIN\UserX',
error code 0x54b.
Could it be that IS_ROLEMEMBER experiences the same problem, but does not print the error?
I just had this same issue... I found that the user in question had server roles also assigned to them. When I removed all server roles except 'public', suddenly the is_rolemember query started correctly reporting a 1 instead of the zero..... I tested this back and forth a few times to confirm.
Also had this issue. Turns out I had to remove sysadmin server role, then it worked.
This is taken from: https://learn.microsoft.com/en-us/sql/t-sql/functions/is-member-transact-sql
Members of the sysadmin fixed server role enter every database as the dbo user. Checking permission for member of the sysadmin fixed server role, checks permissions for dbo, not the original login. Since dbo can't be added to a database role and doesn’t exist in Windows groups, dbo will always return 0 (or NULL if the role doesn't exist).
Try specifying the principal explicitly.
SELECT IS_ROLEMEMBER('my_user', 'SqlLogin')
I tested this and it returned 1.
CREATE DATABASE TestDatabase;
GO
USE TestDatabase;
GO
CREATE ROLE TestRole AUTHORIZATION dbo;
GO
CREATE USER TestUser WITHOUT LOGIN;
GO
EXEC sp_addrolemember 'TestRole', 'TestUser';
GO
SELECT IS_ROLEMEMBER('TestRole', 'TestUser');
GO
I am trying to create a SQL server login and database user from within my application, along with a custom application user row. I want these users to be able to create other users - i.e. the application will control who can/can't create users but I need all users to have permissions for creating SQL server logins and database users.
I have got the server login permissions working - i.e. an existing user/login can create a new login - by adding the logins to the 'securityadmin' server role - which grants the 'ALTER ANY LOGIN' privilege.
I tried to do the same with the database users - adding them to the 'db_accessadmin' database role - which supposedly grants the ALTER ANY USER privilege, which is required for CREATE USER.
However any time I try to create a new database user using a user with the above privileges I get a permissions exception.
I have tried manually granting the ALTER ANY USER permission to a particular user (GRANT ALTER ANY USER TO demouser) but this doesn't work either.
Technically, yes. Whether it's right or wrong... no comment.
Anyway, database security is split into 2 functions:
db_accessadmin to manage users (or "ALTER ANY USER" permission as you mentioned)
db_securityadmin allows you to manage roles memberships and object permissions (or "ALTER ANY ROLE permission)
This is mentioned for sp_addrolemember.
You are actually changing the role, not the user, by running sp_addrolemember so "ALTER ANY ROLE" is enough without having full db_owner rights.
My bad - I have found the issue - it was not the CREATE USER that was failing, but a subsequent call to 'sp_addrolemember'. This requires further permissions that I wasn't assigning.
In particular I needed to add my users to the db_owner database role in order to allow them to assign other/new users to fixed database roles.
Is there a cleaner way to allow me to achieve what I am trying to do here - i.e. create users that are allowed to create other users?
This seems very dangerous, easily becoming a security nightmare. Not knowing anything about why you think this is the best solution to accomplish your objective I can't really tell you not to do it this way, but wow!! - I would think long and hard about whether this really is necessary. The spider-webbing of users just seems like it could quickly be impossible to manage from a DBA perspective.
Would you not be able to just have one SQL account that has the permissions to add users, and the application uses that every time to add new users? Those users then would not need the ability to add other users. Maybe this won't work for your specific objective, but surely there is some other way.
But having said all that ... no, there is not really a cleaner way. The user would have to be assigned to the correct roles in order to have the ability to later add other users.
/*
TOPIC: create a login ,who can add other logins to databases (securityadmin server role)
*/
USE MASTER
GO
Create login securityTestLogin with password = '##somepassword123'
-----add this to server , this is server level security role -------
EXEC master..sp_addsrvrolemember #loginame = N'securityTestLogin', #rolename = N'securityadmin'
--- first this login should be a user in database where we want to give other users access
USE HTDBA
GO
Create user securityTestLogin for login securityTestLogin
EXEC sp_addrolemember N'db_accessadmin', N'securityTestLogin'
-- depends on your requriemtnt you might also want this permission too
--EXEC sp_addrolemember N'db_securityadmin', N'securityTestLogin'
GO
------ Now we think about adding other users to different database roles -------------
/*
There is one gottcha , db_securityadmin role cannot add users to the fixed database roles ,only
db_owner can perform this action , but for security we don't want to give this permission .
so we need a work around
Create a role with required permission and then add users to that role.
*/
--Create user defined database role Readers
EXEC sp_addrole DBUser
-- Add this role to fixeddbroles to get database level permission
EXEC sp_addrolemember db_datareader, DBUser
EXEC sp_addrolemember db_datawriter, DBUser
GO
--------READY TO TEST --------
------ we are using this sample login for test
use master
Go
Create login testlogin1 with password='##somepassword123'
use HTDBA
go
Create user testlogin1 for login testlogin1
--- now add this user to user created DBUser role .
EXEC sp_addrolemember DBUser, testlogin1
A very good article on SQL permissions:
http://www.sqlservercentral.com/articles/Security/sqlserversecurityfixeddatabaseroles/1231/