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/
Related
Big question: How to rotate passwords in an Oracle database in a zero downtime (ZDT) way?
My current thought is to rotate the users. Originally, I had MY_USER that had all the tables and such. Now, I have:
CREATE USER MY_USER NO AUTHENTICATION;
GRANT CREATE SESSION TO MY_USER;
CREATE USER MY_USER_PROXY_1 IDENTIFIED BY "abc123";
GRANT CREATE SESSION TO MY_USER_PROXY_1;
ALTER USER MY_USER GRANT CONNECT THROUGH MY_USER_PROXY_1;
When I want to rotate the password, I simply create MY_USER_PROXY_2 and give the 'connect through' grant to MY_USER. This way, the app can continue to create new connections until I deploy it using the new user. Because of the 'connect through', the new user is essentially the same as the old user so everything should continue to work without much fanfare. Afterwards, I can decommission MY_USER_PROXY_1 or let the password normally expire
This seems like a reasonable approach if there is 1 'physical' user (MY_USER)
However, I am already using proxy users for multi-tenancy. Same as before, but instead of 1 user, there could be hundreds of users going through the same proxy user:
CREATE USER TENANT_PROXY_1 IDENTIFIED BY "abc123";
GRANT CREATE SESSION TO TENANT_PROXY_1;
-- During tenant onboard
CREATE USER TENANT_1234 NO AUTHENTICATION;
GRANT CREATE SESSION TO TENANT_1234;
ALTER USER TENANT_1234 GRANT CONNECT THROUGH TENANT_PROXY_1;
The issue with creating TENANT_PROXY_2 is recreating all the connect through grants. I could iterate through all the users like 'TENANT_%' and apply the grant that way but will always be a window of opportunity after TENANT_PROXY_2 is created and updated with the grants BUT BEFORE the app is restarted to use the new proxy user. So it would add the grant to TENANT_PROXY_1 and thus fail when the proxy user is rotated to TENANT_PROXY_2
I tried using roles (both as the connector and the connectee) but looks like only users are supported:
ALTER USER TENANT_1234 GRANT CONNECT THROUGH TENANT_PROXY_ROLE;
GRANT ROLE TENANT_PROXY_ROLE TO TENANT_PROXY_1;
-- or
ALTER ROLE TENANT_PROXY_ROLE GRANT CONNECT THROUGH TENANT_PROXY_1;
GRANT ROLE TENANT_PROXY_ROLE TO TENANT_1234;
My only thought is to pre-create TENANT_PROXY_1 through TENANT_PROXY_N and apply the grant to all N proxy users during onboarding and manually round-robin through the N users. Not quite as graceful, but still seems reasonable
Any thoughts on either solution? Databases have been around for decades, is there any official solution or pattern to ZDT password rotation problem?
What is the best-practice to create a read-only user for a specific database?
I created a new user and granted the db_datareader role, however, this user still has access to the master db and other system databases. is that ok? or should i deny access on some system tables/databases as well to make it more secure?
Thanks.
Ok, so if i create a new user, will he have any more default permissions i have to deny?
if i do
~create login
~create user for login..
~grant EXECUTE for user
will the user only have EXECUTE permissions or will he have additional permissions as well for the active database?
Hi I believe the user can view other database in the object explorer too.
CREATE LOGIN me with password = 'me', check_policy = off
sp_changedbowner 'me'
GO
USE MASTER
GO
DENY VIEW ANY DATABASE TO me
GO
Well you can use denywrite as an role option. The user has to "see" the master, because the master contains the list of databases that he will enventually connect to, but he will only have guest privalages there. You can then deny access to other specific databases. AFAIK he does not need to see tempdb or msdb as its the SQL engine that accesses these
I'm having problems executing a function.
Here's what I did:
Create a function using SQL Server Management Studio. It was successfully created.
I then tried executing the newly created function and here's what I get:
The EXECUTE permission was denied on
the object 'xxxxxxx', database
'zzzzzzz', schema 'dbo'.
Sounds like you need to grant the execute permission to the user (or a group that they a part of) for the stored procedure in question.
For example, you could grant access thus:
USE zzzzzzz;
GRANT EXEC ON dbo.xxxxxxx TO PUBLIC
Best solution that i found is create a new database role i.e.
CREATE ROLE db_executor;
and then grant that role exec permission.
GRANT EXECUTE TO db_executor;
Now when you go to the properties of the user and go to User Mapping and select the database where you have added new role,now new role will be visible in the Database role membership for: section
For more detail read full article
In SQL Server Management Studio, go to security->schema->dbo:
Double-click dbo, select the Permissions page, then click the "View database permissions" link in blue:
Select the user for whom you want to change permissions, and look for the "Execute" permission under the "explicit" tab:
Choose the appropriate permission by checking the appropriate box.
you need to run something like this
GRANT Execute ON [dbo].fnc_whatEver TO [domain\user]
This will work if you are trying to Grant permission to Users or roles.
Using Microsoft SQL Server Management Studio:
Go to: Databases
Right click on dbo.my_database
Choose: Properties
On the left side panel, click on: Permissions
Select the User or Role and in the Name Panel
Find Execute in in permissions and checkmark: Grant,With Grant, or Deny
Giving such permission can be dangerous, especially if your web application uses that same username.
Now the web user (and the whole world wide web) also has the permission to create and drop objects within your database. Think SQL Injection!
I recommend granting Execute privileges only to the specific user on the given object as follows:
grant execute on storedProcedureNameNoquotes to myusernameNoquotes
Now the user myusernameNoquotes can execute procedure storedProcedureNameNoquotes without other unnecessary permissions to your valuable data.
You don't have the right to execute it, although you have enough permissions to create it.
For more information, see GRANT Object Permissions (Transact-SQL)
If you have issues like the question ask above regarding the exception thrown when the solution is executed, the problem is permission, not properly granted to the users of that group to access the database/stored procedure. All you need do is to do something like what i have below, replacing mine with your database name, stored procedures (function)and the type of permission or role or who you are granting the access to.
USE [StableEmployee]
GO
GRANT EXEC ON dbo.GetAllEmployees TO PUBLIC
/****** Object: StoredProcedure [dbo].[GetAllEmployees] Script Date: 01/27/2016 16:27:27 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[GetAllEmployees]
as
Begin
Select EmployeeId, Name, Gender, City, DepartmentId
From tblEmployee
End
here is how to give permission for one user not public,
Direct Query:
Use MyDatabase
Grant execute on [dbo].[My-procedures-name] to [IIS APPPOOL\my-iis-pool]
Go
You can give everybody execute permission:
GRANT Execute on [dbo].your_object to [public]
"Public" is the default database role that all users are a member of.
If you make this user especial for a specific database, then maybe you do not set it as db_owner in "user mapping" of properties
I have faced the same problem and I solved as give db_owner permission too to the Database user.
The general answer is to grant execute permission as explained above. But that doesn't work if the schema owner of SP is different to underlying objects.
Check schema owners by:
select name, USER_NAME(s.principal_id) AS Schema_Owner from sys.schemas s
To change the owner of an schema you can:
ALTER AUTHORIZATION ON SCHEMA::YOUR_SCHEMA TO YOUR_USER;
Examples:
ALTER AUTHORIZATION ON SCHEMA::Claim TO dbo
ALTER AUTHORIZATION ON SCHEMA::datix TO user1;
Finally if within your SP you are truncating a table or changing structure you may want to add WITH EXECUTE AS OWNER in your SP:
ALTER procedure [myProcedure]
WITH EXECUTE AS OWNER
as
truncate table etl.temp
If you only need to grant a single function then (only db admin can do it):
Open Management studio
Find function/procedure you want to grant in Object Eplorer (dbname-Programmability-[Functions/Stored Procedures]-...)
Right click on function or procedure name and open Properties
In Properties select Permissions, add user (or schema) you want and Grant him Execute permission.
I believe this is most secure way how to do it because you only grant to user execution of this function. Nothing else!
I think you have to select the object you want to grant access to, then right-click, and select properties. Select permission on the modal window that will be displayed then click on Search, on the newly revealed window, select browse, select the user you want to grant access and click on ok. it will display for you a list of permission and the grant status, and then you can choose to grant or deny
This shows that you don't have access to perform any action on the specified database table. To enable this, Go to Security -> Schema and check.
you'd better off modifying server roles, which was designed for security privileges. add sysadmin server role to your user. for better security you may have your custom server roles. but this approach will give you what you want for now.
Object Explorer -> Server -> Security -> Logins
Right click on your desired user
Go to Server Roles on left hand side
Make sure sysadmin is checked
Hit OK and restart your SQL server
Good luck
How do I create a MS SQL server user that only allowed to read certain views of a particular database?
Here's a script that creates a new user and gives him select only permissions on a specific view.
USE [master]
GO
CREATE LOGIN [LimitedUser] WITH PASSWORD=N'testPass',
DEFAULT_DATABASE=[master],
CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
USE [TestDB]
GO
CREATE USER [LimitedUser] FOR LOGIN [LimitedUser]
GO
use [TestDB]
GO
GRANT SELECT ON [dbo].[myView] TO [LimitedUser]
GO
Edit
Instead of doing this for a specific user you might want to consider using Roles instead.
USE [TestDB]
GO
CREATE ROLE [LimitedRole]
GO
GRANT SELECT ON [dbo].[TestView] TO [LimitedRole]
GO
EXEC sp_addrolemember N'LimitedRole', N'LimitedUser'
GO
This way if you have multiple users for example in a Windows Authenitcation Mode you might have many users, all can be granted access to this role. This way as you add / remove views you don't have to touch every user.
The trick to doing this is to not give any explicit permissions to the Public role. Every user is irrevocably a member of that role so there is no way to prevent any user of the DB from having any rights you give to Public.
Aside from that, you just add the user to the appropriate DB and only give them rights to the objects you are interested in.
how do you create a new database user with password in sql server 2005?
i will need this user/password to use in the connection string eg:
uid=*user*;pwd=*password*;
CREATE LOGIN [user] WITH PASSWORD='password',
DEFAULT_DATABASE=[your_db], CHECK_POLICY=OFF
GO
CREATE USER [user] FOR LOGIN [user]
EXEC sp_addrolemember N'db_datareader', N'your_db'
EXEC sp_addrolemember N'db_datawriter', N'your_db'
GO
Where CHECK_POLICY=OFF switches off password complexity check, etc
As of SQL Server 2005, you should basically create users in two steps:
create a "login" to your SQL Server as a whole
create users for this login in each database needed
You'd go about doing this like so:
CREATE LOGIN MyNewUser WITH PASSWORD = 'top$secret';
And the "USE" your database and create a user for that login:
USE AdventureWorks;
CREATE USER MyNewUser FOR LOGIN MyNewUser
As indicated, use the CREATE LOGIN to create the ability to connect to SQL Server as that account. Then use CREATE USER within the database to give that login the ability to access the database in question.
However, a few security points based on some of these comments:
If at all possible, you want to use Windows authentication, not a SQL Server based login (which is what you are doing when you use user/pwd in this manner). If you are running from a computer on the same domain as SQL Server, you can use a service account that is a Windows user account. This ensures the domain is the single source for security.
You didn't say what rights the user needed. Avoid using db_datareader and db_datawriter roles whenever possible. They give IMPLICIT access to tables and views and if someone is performing a quick permissions check on the database, they may not think to check the membership in these roles. That means your reporting on security is using. Best practices say to create your own database role, assign permissions to it, and make the user a member of that role.
Whenever possible, use a strong password. One example had the password policies turned off. SQL Server will use the password policy from the local server (which is usually set at the domain level). You want to maintain that strong password policy, if possible.
You'll have to create it first as a user, and then set up the correct permissions for the user.
you'll have to ensure that your DB is configured with both User auth and SQL auth
If using the Management Studio: right-click on the Server, select "Security" ensure that server authentication is "SQL Server and Windows Authentication mode"
in Security-logins, right click and select "New Login", select SQL Authentication, use the username and password you like.
USE [master]
GO
CREATE LOGIN [ test] WITH PASSWORD=N'test', DEFAULT_DATABASE=[MY_DATABASE], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
GO
on the DB you want, in security, users, select new User. Select a username, and attach the login name you've just created, and select the roles you want to apply to this user (i.e. db_datareader, db_datawriter):
USE [MY_DATABASE]
GO
CREATE USER [myDefaultUser] FOR LOGIN [ test]
GO
USE [MY_DATABASE]
GO
EXEC sp_addrolemember N'db_datareader', N'myDefaultUser'
GO
USE [MY_DATABASE]
GO
EXEC sp_addrolemember N'db_datawriter', N'myDefaultUser'
GO
That is it. Now you can create your connection string using this password.
CREATE LOGIN MyNewUser WITH PASSWORD = 'top$secret'
USE AdventureWorks
CREATE USER MyNewUser FOR LOGIN MyNewUser
GO
USE [MASTER]
EXEC master.dbo.sp_addlogin #loginame = N'USERNAME', #passwd = 'THEPASS' #defdb = N'master', #deflanguage = N'us_english'
USE [YOUR_DB]
EXEC dbo.sp_grantdbaccess #loginame = N'USERNAME', #name_in_db = N'USERNAME'