Error with SQL Server "EXECUTE AS" - sql-server

I've got the following setup:
There is a SQL Server DB with several tables that have triggers set on them (that collect history data). These triggers are CLR stored procedures with EXECUTE AS 'HistoryUser'. The HistoryUser user is a simple user in the database without a login. It has enough permissions to read from all tables and write to the history table.
When I backup the DB and then restore it to another machine (Virtual Machine in this case, but it does not matter), the triggers don't work anymore. In fact, no impersonation for the user works anymore. Even a simple statement such as this
exec ('select 3') as user='HistoryUser'
produces an error:
Cannot execute as the database principal because the principal "HistoryUser" does not exist, this type of principal cannot be impersonated, or you do not have permission.
I read in MSDN that this can occur if the DB owner is a domain user, but it isn't. And even if I change it to anything else (their recommended solution) this problem remains.
If I create another user without login, I can use it for impersonation just fine. That is, this works just fine:
create user TestUser without login
go
exec ('select 3') as user='TestUser'
I do not want to recreate all those triggers, so is there any way how I can make the existing HistoryUser work?

Detect Orphaned Users, then resolve by linking to a login.
DETECT:
USE <database_name>;
GO;
sp_change_users_login #Action='Report';
GO;
RESOLVE:
The following command relinks the server login account specified by <login_name> with the database user specified by <database_user>:
USE <database_name>;
GO
sp_change_users_login #Action='update_one', #UserNamePattern='<database_user>',
#LoginName='<login_name>';
GO
https://msdn.microsoft.com/en-us/library/ms175475.aspx

What user account does the trigger execute as.
You'll need to grant that user IMPERSONATE priviledges for the User Account HistoryUser.
GRANT IMPERSONATE ON USER:: YourUser TO HistoryUser
More details here
http://msdn.microsoft.com/en-us/library/ms181362.aspx

Problems like this that arise after moving a database from one machine to another usually involve mismatched SID's, although I'm not sure if or how it applies to your case. Try dropping and re-creating the database user, making sure to reinstate its permissions to those tables.

It is an "orphaned user". It wont work. Documentation states this clear.
:-(
Fix "orphaned user" state and it will work again

Related

SQL owner chaining

Basically I have a front end application called AdminProgram. In SQL Server I have a role called AdminProgramUsers.
Now this role has permissions to various SPs and the like but, crucially, there is no select permission on any table. Everything they see or modify is done through SPs.
Now I've just written a new SP for them. I have had no choice but to use dynamic SQL, that is constructing the actual SQL query in a String variable called #FinalQuery and then running EXECUTE #FinalQuery.
Now initially I was getting a lot of user doesn't have access to the tables, needed to either grant SELECTs to the columns in question, but that solution won't work due to internal politics.
The other thing I seem to understand is that I need to use EXECUTE AS somehow. I have Googled, but I'm struggling to get this right.
And to pre-emptively answer a couple of questions, there is no option but to use dynamic SQL in this SP much to my displeasure, we're talking about SQL Server 2005 and there will be no way of signing any SPs with certificates (mainly as the DBA will flip a nut at the prospect of anything complicated).
So... I think the answer lies somewhere in EXECUTE AS with ownership chaining... but I need to know how to do it... assuming that the role available is AdminProgramUsers...
The current solution I have is:
CREATE SP MySp AS
DECLARE #FinalTable (columns)
DECLARE #FinalQuery
SET #FinalQuery = "EXECUTE AS CALLER
SELECT blah blah"
INSERT #FinalTable
EXECUTE (#QueryString) AS user ='AdminProgramUsers'
Do some more processing on #FinalTable
Select * from #FinalTable
The error I get is:
Unexpected Error in My Sp
Cannot execute as the database principal because the principal "AdminProgramUsers" does not exist, this type of principal cannot be impersonated, or you do not have permission.
here is an excerpt from ms documentation about execute on sql server 2005:
The user or login name specified in AS { LOGIN | USER } = ' name '
must exist as a principal in sys.database_principals or
sys.server_principals, respectively, or the statement will fail.
Additionally, IMPERSONATE permissions must be granted on the
principal. Unless the caller is the database owner or is a member of
the sysadmin fixed server role, the principal must exist even when the
user is accessing the database or instance of SQL Server through a
Windows group membership.
in your code you feed the execute a role but a user or login is expected instead.
the above text is not very clear if you don't read this:
LOGIN
Specifies the context to be impersonated is a login. The scope
of impersonation is the server.
USER
Specifies the context to be
impersonated is a user in the current database. The scope of
impersonation is restricted to the current database. A context switch
to a database user does not inherit the server-level permissions of
that user.
you can specify a user or a login as impersonation context; a role is neither a login nor a user.

Cannot find the user '', because it does not exist or you do not have permission

I am trying to add permissions to a Store procedure for a user using this query,
USE [MyDatabaseName]
GO
GRANT EXEC ON [dbo].[StoreProcedureName] TO [UserName]
GO
I can give permissions to user through theUser Interface but using this query I get this error,
Cannot find the user 'UserName', because it does not exist or you do not have
permission.
If I don't have permissions then how can I add permissions using User Interface.
I just encountered the same problem.
Make sure there is a user mapping for your login in the master table. No database role memberships are required, just tick 'Map' for the database master under 'User Mapping' in the properties for the login 'UserName'.
Run this:
USE [db_where_you_need_access]
GO
CREATE USER [your_user] FOR LOGIN [your_user]
I had this issue and yet I am in the local admin group on the server. Apparently if UAC is turned onrunning SQL Server Management Studio as administrator makes a world of difference. I didn't have any permissions until I did this.
You can get problems like this when a database has been restored from another server and the GUID of the user in the database is different from that of the current server.
This will re-link orphaned users:
USE <database_name>;
GO
sp_change_users_login #Action='update_one', #UserNamePattern='<database_user>',
#LoginName='<login_name>';
GO
other than this, if the user exists and you have the relevant security rights, there is no reason what you doing wouldn't work.
A bit of a daft one, but make sure your UserName is spelt correctly in the GRANT statement. I spent half an hour trying to figure out what the cause of this error was and it was simply a typo on my part!

Sql server execute permission; failure to apply permissions

I've just migrated from SQL2000 to SQL2008 and I have started getting an execute permission issue on a stored proc which uses sp_OACreate.
The rest of the system works fine with the db login which has been setup and added to the database.
I've tried:
USE master
GO
GRANT EXEC ON sp_OACreate TO [dbuser]
GO
But this fails with the following error:
Msg 15151, Level 16, State 1, Line 1
Cannot find the user 'dbuser', because
it does not exist or you do not have
permission.
I'm logged into the server as sa with full permissions. I can execute a similar sql statement and apply the permissions to a server role, however not a login/user.
How do I apply the changes to the specific user/login?
I can apply the permissions to the public role and it resolves my issue; however this seems to be a security issue to me which I don't really want to apply to the live server.
Leading on from John's answer I checked the user listings on the Master database and my user wasn't there. Whether it had been deleted or lost some how I don't know. Something may have gone crazy with the migration of the dbs to the new server instance.
Anyway; re-creating the user and associating it to the specific login enabled me to run the following statements on the master database to allow for the execution of the stored procs.
USE MASTER
GO
GRANT EXECUTE ON [sys].[sp_OADestroy] TO [dbuser]
GO
GRANT EXECUTE ON [sys].[sp_OACreate] TO [dbuser]
GO
GRANT EXECUTE ON [sys].[sp_OAMethod] TO [dbuser]
GO
GRANT EXECUTE ON [sys].[sp_OASetProperty] TO [dbuser]
GO
Thanks for all the help and pointers. Hope this helps other people in the future.
The error suggests that the User "dbuser" does not exist in the master database.
I assume the user exists within the master database?
You can check by using the following T-SQL
USE MASTER;
GO
SELECT *
FROM sys.sysusers
WHERE name = 'dbuser'
If the user turns out not to exist, simply use the CREATE USER statement and create a user called "dbuser". The user will automatically be mapped to a Login of the same name, provided one exists.
Your problem could be related to orphaned users.
Try
USE MASTER
GO
EXEC sp_change_users_login 'Report'
This will return one row per orphaned user name. Then,
EXEC sp_change_users_login 'Update_One', 'dbuser', 'dbuser'
Here is some code I'm using the verify that (current user) has EXECUTE permission on sp_OACreate etc:
use master;
select state_desc,name from
sys.database_permissions a
left join
sys.all_objects b
on a.major_id = b.object_id
where name like 'sp_OA%';
As pointed out by #John Sansom and #WestDiscGolf the user has to exist in the Master database and the execution rights must granted in the Master database, hence use Master is required. The query above will return records if the user has execute permissions and empty set if they do not. (Execution in the user database will also return empty set.)
I couldn't figure out a way check these permissions using fn_my_permissions, which is supposedly the right tool for jobs like this.
Check if your user has permissions for the database you use. You can do this by Security -> Logins -> Select User and open the properties window. Then select "User Mapping" from the right menu. Now check the databases that you want the given user to have access to. After that select from the bottom part of the window "Database role membership" and check "db_owner". Now the user will be the owner of the database and will be able to execute queries, store procedures and so on.
UPDATE:
Add user for the database by selecting your database -> security -> users -> right click "New User"
Or you can use this query
CREATE LOGIN AbolrousHazem
WITH PASSWORD = '340$Uuxwp7Mcxo7Khy';
USE AdventureWorks2008R2;
CREATE USER AbolrousHazem FOR LOGIN AbolrousHazem;
GO
Here are more details http://msdn.microsoft.com/en-us/library/ms173463.aspx

SQL Server db_owner

in my SQL2008 I have a user which is in the "db_datareader", "db_datawriter" and "db_ddladmin" DB roles, however when he tries to modify a table with SSMS he receives a message saying:
You are not logged in as the database owner or system administrator. You might not be able to save changes to tables that you do not own.
Of course, I would like to avoid such message, but until now I did find the way...
Therefore, I try to modify the user by adding him to the "db_owner" role, and of course I do not have the message above.
My question is:
Is it possible to keep the user in the "db_owner" role, but deny some actions like alter user or ? I try "alter any user" securable on DB level, but it does not work...
THANKS!
If the user is part of db_ddladmin it shouldn't be a problem. This is just a warning
Members of the db_ddladmin fixed database role can run any Data Definition Language (DDL) command in a database. It is probably just a warning from SSMS, try it out create a user and try to alter some tables
My understanding has always been that any user with db_owner rights can do anything to a database, up to and including dropping it. Certainly, this was true through SQL 2005. I've heard nothing to imply that this has changed with SQL 2008.
Those are indeed warnings, and I don't see any way to disable that type of warning in SSMS.
In 2008R2 the behavior I'm seeing is users with "db_datareader", "db_datawriter" and "db_ddladmin" still need to be granted view definition to be able to make edits in SSMS by right-clicking and selecting design. If you haven't granted view definition, then the design view will open (with warnings) read-only.
See: MSFT Connect Bug
To me it seems more discoverable to assign view definition permissions to your ddladmin users through a role, rather than doing it for specific user accounts as stated in the workaround on Connect. This will add a db_definitionviewer database role:
USE <DB Name>;
CREATE ROLE db_definitionviewer;
GRANT VIEW DEFINITION TO db_definitionviewer;
EXEC sp_addrolemember 'db_definitionviewer', '<DOMAIN\group> | <DOMAIN\User>';

How to disable SQL Server Management Studio for a user

Is there a way to prevent users from getting into SQL Server Management Studio so that they can't just edit table rows manually? They still need to access the tables by running my application.
You can use the DENY VIEW ANY DATABASE command for the particular user(s). This is a new feature available in SQL Server 2008.
It prevents the user from seeing the system catalog (sys.databases, sys.sysdatabases, etc.) and therefore makes the DB invisible to them in SQL Management Studio (SSMS).
Run this command from the Master Database:
DENY VIEW ANY DATABASE TO 'loginName'
The user is still able to access the database through your application. However, if they log in through SSMS, your database will not show up in the list of databases and if they open a query window, your database will not appear in the dropdown.
However, this is not fool-proof. If the user is smart enough to run the Query Command:
USE <YourDatabaseName>
Then they will see the database in the Query Analyzer.
Since this solution is taking you 90% there, I would give the database some obscure name not let the users know the name of the database.
You DO NOT need to worry about them having access to the tool. Simply make sure they do not know any of the SQL logins for the specific Databases that have read/write permissions, if they do, change the password. If they have access to the DB via Windows Authentication, make sure that they are in a datareader role. You can use roles to manage what the users can do in SQL.
You can use a trigger.
CREATE TRIGGER [TR_LOGON_APP]
ON ALL SERVER
FOR LOGON
AS
BEGIN
DECLARE #program_name nvarchar(128)
DECLARE #host_name nvarchar(128)
SELECT #program_name = program_name,
#host_name = host_name
FROM sys.dm_exec_sessions AS c
WHERE c.session_id = ##spid
IF ORIGINAL_LOGIN() IN('YOUR_APP_LOGIN_NAME')
AND #program_name LIKE '%Management%Studio%'
BEGIN
RAISERROR('This login is for application use only.',16,1)
ROLLBACK;
END
END;
https://www.sqlservercentral.com/Forums/1236514/How-to-prevent-user-login-to-SQL-Management-Studio-#bm1236562
I would suggest you lock down the database and give appropriate read-only (or other) rights to the user. That way the user can still use management studio to run select queries and such.
If you don't want the user to have any rights at all then you could do that as well.
If your application is running as a service/user account then only that account requires access to the database. The individual users' account do not require any access to the database and therefore they won't even have read access. Your app will be the gateway to the data.
If the users are running the application under their user accounts then grant them read-only permission. You can simply add them to the db_datareader role.
Hope this helps!
You can deny 'Users' access rights to the ssms.exe executable file, while granting the relevant users/administrators rights to it.
If your application only used stored procedures to modify the data, you could give the end users access to run the stored procs, but deny them access to modify the tables.
Don't let them know what the database login is.
If you can't restrict the login, use stored procedures exclusively for updates and disable any CREATE,DELETE,INSERT, or UPDATE permissions for that user.
An Application Role will allow you to secure database objects to your application instead of the logged on user.
I agree with Jon Erickson as a general rule
do not allow any users access to the tables, but only allow access through stored procs
do not allow general user accounts access to stored procs, but only the account your app runs under (whether it's an integrated login or SQL login)
Make well usage of Database Roles, if Users should only have SELECT (read) access assign them the db_datareader Role. Even if they login using SSMS they will can execute only SELECT statements.

Resources