EXECUTE AS USER = 'dbo' Throws error. Why? - sql-server

When I create a new database and I execute SELECT user it returns me that the user is dbo.
So I was creating a new user and executing the code as that user created. But when trying to change it again to dbo, it throws me an error that it doesn't exist, but I can see it. Why does this happens? I'm executing something wrong?
CREATE USER TestUser WITHOUT LOGIN
SELECT user --Returns dbo
SELECT * FROM sys.database_principals --I can see both, dbo and TestUser and some other users of the system
EXECUTE AS user = 'TestUser'
SELECT user --Returns TestUser
EXECUTE AS user = 'dbo'; -- Says that it doesn't exist
Error that throws:
Cannot execute as the database principal because the principal "dbo"
does not exist, this type of principal cannot be impersonated, or you
do not have permission.
Using Microsoft SQL Server Management Studio 14.0.17119.0

Because "you do not have permission". Everything after EXECUTE AS is done as the new user, including attempting to impersonate new users, and TestUser, not being a sysadmin, cannot impersonate dbo. REVERT instead.

The key is in the error message "this type of principal cannot be impersonated". Basically, user 'dbo' should be considered an alias or a role (database owner). So, when you create a database/table/etc by using your login you have the database owner privilege. For example, if you log in as user 'sa' and create a table, the full qualified table name is DataBaseName.dbo.TableName.
Why would you need to execute as 'dbo'? It would be better not to assign database owner rights to a bunch of users, but rather keep the users/roles/permissions well compartmented.

Related

User can't connect to Azure SQL Instance

I created my first database (let's call it MyDB) on Azure and created a user that I want to use to query the DB from my applications. I only wanted to give that user db_datawriter and db_datareader because I think that is all this user needs to do from the application.
When I run this on MyDB:
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'
ORDER BY DP1.name;
I get this back:
db_accessadmin No members
db_backupoperator No members
db_datareader MyDBUser
db_datawriter MyDBUser
db_ddladmin No members
db_denydatareader No members
db_denydatawriter No members
db_owner dbo
db_securityadmin No members
public No members
so that seemed to work. The problem is - I have to give this user also Permission to connect to the DB in the first place, because when I try to connect to the server, I get this:
===================================
Cannot connect to abc.database.windows.net.
===================================
The server principal "MyDBUser" is not able to access the database "master" under the current security context.
Cannot open user default database. Login failed.
Login failed for user 'MyDBUser'. (.Net SqlClient Data Provider)
I think this is probably, because my new user can't connect to master DB, as the errormessage suggests. However, when I look at the properties of MyDB, "Connect" was granted for the user by dbo
How can I let my user connect to the Azure DB Instance, preferably with as less permission as possible, I would only like for him to select, update, insert etc. on MyDB
I tried to change default DB with this command, so I don't need to do anything on masterDB, but the stored procedure wasn't found:
Exec sp_defaultdb #loginame='MyDBUser', #defdb='MyDB'
Edit: That's how I created the Login / User in SSMS
First (on instance):
CREATE LOGIN MyDBUser
WITH PASSWORD = '******'
GO
Then (on MyDB):
CREATE USER MyDBUser
FOR LOGIN MyDBUser
WITH DEFAULT_SCHEMA = dbo
GO
-- Add user to the database owner role
EXEC sp_addrolemember N'db_datawriter', N'MyDBUser'
GO
You have created a LOGIN and then created a USER for the LOGIN but only in the database you want them to connect to but not in master.
SQL Azure Databases are contained databases, so there is no need to create a LOGIN; the databases use their own scoped credentials.
First DROP the USER and LOGIN you created. Connect to MyDB and DROP the user first:
DROP USER MyDBUser;
Then connect to master and DROP the LOGIN:
DROP LOGIN MyDBUser;
Now connect to MyDB again and CREATE the USER with the needed credentials:
CREATE USER MyDBUser WITH PASSWORD = N'Your Secure Password', DEFAULT_SCHEMA = N'dbo';
Then you can give it the needed database roles. Don't use sp_addrolemember; it has been deprecated for ~10 years.
ALTER ROLE db_datareader ADD MEMBER MyDBUser;
ALTER ROLE db_datawriter ADD MEMBER MyDBUser;
I've had a similar error message when connecting to Azure SQL DB with SSMS. The solution there was to identify the database, hence the message "access the database "master"". You probably have entered the DB server name already.
You do not mention how you are trying to connect to the DB, but in case of SSMS, enter the name of the database on the tab "Connection properties" (available behind the "Options>>>" button on "Connect to Server" screen).

SQL Azure readonly user who cannot delete database

I've created a readonly user ala:
(in master)
CREATE LOGIN reader WITH password='YourPWD';
CREATE USER readerUser FROM LOGIN reader;
(in target db)
CREATE USER readerUser FROM LOGIN reader;
EXEC sp_addrolemember 'db_datareader', 'readerUser';
This works well in denying the user access to do anything but read from tables in the target db.
However it still allows them to delete the target db from management studio.
How can I deny them db deletion rights?
Can you clarify what you mean by DB deletion rights? Do you mean DROP the database? If so, the permission for DROP DATABASE is in master. So ensure that the login is not part of the dbmanager role.
If you meant deleting data from tables then by default users in database do not have that permission unless you add them in roles like db_datawriter or db_owner or grant DELETE permission explicitly.
You can check permissions of user by doing something like:
execute as user = 'readerUser';
select * from fn_my_permissions (NULL, 'DATABASE');
revert;
go

Is it possible to get "WITH EXECUTE AS " working under "dbo user/Administrator login" permissions (VIEW SERVER STATE needed)?

The problem can be emulated this way:
DECLARE #C1 BIGINT,#C2 BIGINT;
PRINT SUSER_NAME()+ ' '+ USER_NAME();
SELECT #C1=transaction_id from sys.dm_tran_current_transaction (nolock)
PRINT #C1
EXECUTE AS USER = 'dbo';
PRINT SUSER_NAME()+ ' '+ USER_NAME();
SELECT #C2=transaction_id from sys.dm_tran_current_transaction (nolock)
PRINT #C2
REVERT;
Called from 'Administrator' login (db owner, linked to dbo user) returns:
Administrator dbo
2209599
Administrator dbo
Msg 297, Level 16, State 1, Line 7
The user does not have permission to perform this action.
The same user but different results. Why?
Details:
I have a SP that contains select from sys.dm_os_sys_info and therefore this SP's caller should have VIEW SERVER STATE permissions.
I have modified SP header with "WITH EXECUTE AS OWNER". Owner is standard 'dbo' database user linked to 'Administrator' server login. Administrator is a member of sysadmin and have effective permission 'VIEW SERVER STATE', but execution of my modified procedure brings the 'The user does not have permission to perform this action' error... I see there logic since DBO database user by itself doesn't have server permissions (even if Administrator login has). But what next?
I have tried:
GRANT VIEW SERVER STATE TO DBO - doesn't work because of 'dbo is
not a user-defined server role' error.
Create new user 'ServerStateViewer' linked to 'Administrator' - doesn't work becuase of 'the login already has an account under a different user name' (as I understand it - dbo user exits in the dabatabse)
Create new user 'ServerStateViewer' not linked to any login - doesn't work because I can't to add any server permissions to this user.
WITH EXECUTE AS 'Administrator' - doesn't work because of 'Administrator is not a database user' error.
So it seems I'm forced to create new server login. I am interesting, may be there are still other ways to get WITH EXECUTE AS working under dbo user / Administrator login permissions?
You'll need to use code signing. This is not a problem, since code signing is what you should be using to start with to grant permission to procedures... The proper sequence is this:
inspect the procedure code to ensure that you trust it
change the procedure to have an EXECUTE AS OWNER clause
create a certificate with a private key in the SP's database
sign the procedure with the private key of the certificate you created
drop the private key of the certificate (to prevent it from ever being used again)
copy the certificate into the master database
create a login from the certificate
grant AUTHENTICATE SERVER to the certificate derived login
grant any additional priviledge required by the procedure (e.g. VIEW SERVER STATE) to the certificate derived login
For an example see Signing an activate procedure.
Note that during development code signing can be a pain because you will have to re-sign the procedure after every change to it. For dev purposes, do not drop the private key right after signing, so it can be reused.

How do I create a new user in a SQL Azure database?

I am trying to use the following template:
-- =================================================
-- Create User as DBO template for SQL Azure Database
-- =================================================
-- For login <login_name, sysname, login_name>, create a user in the database
CREATE USER <user_name, sysname, user_name>
FOR LOGIN <login_name, sysname, login_name>
WITH DEFAULT_SCHEMA = <default_schema, sysname, dbo>
GO
-- Add user to the database owner role
EXEC sp_addrolemember N'db_owner', N'<user_name, sysname, user_name>'
GO
I would like to create a user called user1 with a password of 'user1pass'. I connected with my default database 'authentication' and I have a query window open.
But the template does not make sense for me. For example what's sysname, where do I supply the password and what should I use as the default_schema?
The particular user needs to have the power to do everything. But how do I set it up so he can do everything, is that done if I make the user a database owner?
So far I have tried:
CREATE USER user1, sysname, user1
FOR LOGIN user1, sysname, user1
WITH DEFAULT_SCHEMA = dbo, sysname, dbo
GO
Giving:
Msg 102, Level 15, State 1, Line 1 Incorrect syntax near ','.
and:
CREATE USER user1
FOR LOGIN user1
WITH DEFAULT_SCHEMA = dbo
GO
Giving:
Msg 15007, Level 16, State 1, Line 1 'user1' i
s not a valid login or you do not have permission.
Edit - Contained User (v12 and later)
As of Sql Azure 12, databases will be created as Contained Databases which will allow users to be created directly in your database, without the need for a server login via master.
Sql (standard) User
CREATE USER [MyUser] WITH PASSWORD = 'Secret';
ALTER ROLE [db_datareader] ADD MEMBER [MyUser]; -- or sp_addrolemember
AAD linked User
CREATE USER [SomeUser#mydomain.com] FROM EXTERNAL PROVIDER;
EXEC sp_addrolemember 'db_datareader' , N'SomeUser#mydomain.com'
AAD linked Group
CREATE USER [SomeGroup] FROM EXTERNAL PROVIDER;
EXEC sp_addrolemember 'db_datareader' , N'SomeGroup'
NB! when connecting to the database when using a contained user that you must always specify the database in the connection string.
Traditional Server Login - Database User (Pre v 12)
Just to add to #Igorek's answer, you can do the following in Sql Server Management Studio:
Create the new Login on the server
In master (via the Available databases drop down in SSMS - this is because USE master doesn't work in Azure):
create the login:
CREATE LOGIN username WITH password=N'password';
Create the new User in the database
Switch to the actual database (again via the available databases drop down, or a new connection)
CREATE USER username FROM LOGIN username;
(I've assumed that you want the user and logins to tie up as username, but change if this isn't the case.)
Now add the user to the relevant security roles
EXEC sp_addrolemember N'db_owner', N'username'
GO
(Obviously an app user should have less privileges than dbo.)
Check out this link for all of the information : https://azure.microsoft.com/en-us/blog/adding-users-to-your-sql-azure-database/
First you need to create a login for SQL Azure, its syntax is as follows:
CREATE LOGIN username WITH password='password';
This command needs to run in master db. Only afterwards can you run commands to create a user in the database. The way SQL Azure or SQL Server works is that there is a login created first at the server level and then it is mapped to a user in every database.
HTH
I followed the answers here but when I tried to connect with my new user, I got an error message stating "The server principal 'newuser' is not able to access the database 'master' under the current security context".
I had to also create a new user in the master table to successfully log in with SSMS.
USE [master]
GO
CREATE LOGIN [newuser] WITH PASSWORD=N'blahpw'
GO
CREATE USER [newuser] FOR LOGIN [newuser] WITH DEFAULT_SCHEMA=[dbo]
GO
USE [MyDatabase]
CREATE USER newuser FOR LOGIN newuser WITH DEFAULT_SCHEMA = dbo
GO
EXEC sp_addrolemember N'db_owner', N'newuser'
GO
You can simply create a contained user in SQL DB V12.
Create user containeduser with password = 'Password'
Contained user login is more efficient than login to the database using the login created by master. You can find more details # http://www.sqlindepth.com/contained-users-in-sql-azure-db-v12/
I use the Azure Management console tool of CodePlex, with a very useful GUI, try it. You can save type some code.
1 Create login while connecting to the master db
(in your databaseclient open a connection to the master db)
CREATE LOGIN 'testUserLogin' WITH password='1231!#ASDF!a';
2 Create a user while connecting to your db (in your db client open a connection to your database)
CREATE USER testUserLoginFROM LOGIN testUserLogin;
Please, note, user name is the same as login. It did not work for me when I had a different username and login.
3 Add required permissions
EXEC sp_addrolemember db_datawriter, 'testUser';
You may want to add 'db_datareader' as well.
list of the roles:
https://learn.microsoft.com/en-us/sql/relational-databases/security/authentication-access/database-level-roles?view=sql-server-ver15
I was inspired by #nthpixel answer, but it did not work for my db client DBeaver.
It did not allow me to run USE [master] and use [my-db] statements.
https://azure.microsoft.com/en-us/blog/adding-users-to-your-sql-azure-database/
How to test your user?
Run the query bellow in the master database connection.
SELECT A.name as userName, B.name as login, B.Type_desc, default_database_name, B.*
FROM sys.sysusers A
FULL OUTER JOIN sys.sql_logins B
ON A.sid = B.sid
WHERE islogin = 1 and A.sid is not null
List of all users in Azure SQL
create a user and then add user to a specific role:
CREATE USER [test] WITH PASSWORD=N'<strong password>'
go
ALTER ROLE [db_datareader] ADD MEMBER [test]
go
I found this link very helpful:
https://azure.microsoft.com/en-gb/documentation/articles/sql-database-manage-logins/
It details things like:
- Azure SQL Database subscriber account
- Using Azure Active Directory users to access the database
- Server-level principal accounts (unrestricted access)
- Adding users to the dbmanager database role
I used this and Stuart's answer to do the following:
On the master database (see link as to who has permissions on this):
CREATE LOGIN [MyAdmin] with password='ReallySecurePassword'
And then on the database in question:
CREATE USER [MyAdmin] FROM LOGIN [MyAdmin]
ALTER ROLE db_owner ADD MEMBER [MyAdmin]
You can also create users like this, according to the link:
CREATE USER [mike#contoso.com] FROM EXTERNAL PROVIDER;
I think the templates use the following notation: variable name, variable type, default value.
Sysname is a built-in data type which can hold the names of system objects.
It is limited to 128 Unicode character.
-- same as sysname type
declare #my_sysname nvarchar(128);

Select permission denied for user who is db_owner in SQL Server

Using SQL Server 2008.
I created a new database, created a new user and mapped the user to the same login name.
Gave the user all the roles available including db_owner.
The user created a new table but when the user tried to select from the table, an error "The SELECT permission was denied on the object ...." showed up.
Why doesn't the user have select permission if the user is member of the db_owner and db_datareader roles?
I recall this used to work before.
MOst likely the user isn't actually the DBO. Check the table name is [dbo].[tablename] and that the user actually is the dbo.
Actually - More information about the error would be nice. Cause you usually have select access to tables you have created.
Are there any deny permissions set?

Resources