I want to update a table in databse B, from a trigger in database A. The trigger in database A is fired via different user accounts, which may or may not have permission on Database B. It works fine with the users which have permission on database B.
However, when trigger is fired under a user account, it throws exception because user does not have permission on the object referred by the Synonym. Is there a way to check permission on the object referred by Synonym so that I can avoid the exception when user does not have permission?
Finally, I found it in documentation. Below query did the trick.
IF (SELECT HAS_PERMS_BY_NAME('ams.syn_bkgsvcattribute', 'OBJECT', 'INSERT'))>0
print 'yes'
else
print 'no'
Related
A user had an issue with a login to an application. The error is "The Update permission was denied on the object '{tablename}', database '{databasename}, schema 'dbo'.
The user already has permissions based on a role that already allowed other users to properly login, making the necessary entry into the "log" table.
When checking the user with this code,
EXECUTE AS LOGIN = N'[AD UserName]';
SELECT
permission_name AS [Permission]
FROM fn_my_permissions(N'[ServerName]', N'DATABASE')
ORDER BY permission_name;
REVERT;
the results were:
CONNECT
EXECUTE
SELECT
VIEW ANY COLUMN ENCRYPTION KEY DEFINITION
VIEW ANY COLUMN MASTER KEY DEFINITION
I expected this:
CONNECT
DELETE
EXECUTE
INSERT
SELECT
UPDATE
VIEW ANY COLUMN ENCRYPTION KEY DEFINITION
VIEW ANY COLUMN MASTER KEY DEFINITION
I granted Insert, Update, Delete and Execute directly to the user for the database. The permissions were still not showing Insert, Execute or Delete and still the user can not log in.
I applied permissions directly to the table. Again the user could not access the application due to the error when inserting into the table.
Additionally the user has access to other DB's on the server but I am not able to find why on this database the user's granted permissions are not correctly applied.
Where can I find if permissions are being altered due to server level permissions or other ideas i am not able to think of.
Thank you in advance
The issue was the user was part of a group that had db_denywriter checked on the same database.
The question still remains what is the best way to determine the permissions of a user, even if it's through a group permission, are denied or granted.
The lack of something should not equate to true, or false.
Thanks!
I am working on a Database project in VS2013 that contains a C# SQL CLR stored procedure.
The assembly owner is [servername\User123]
The database owner is also [servername\User123] (Being the database owner, this user obviously already exists on the server. I managed a successful publish of the database by commenting out the code in my SQL CLR procedure and publishing, the following occurs after I un-comment-out that code.)
If I try to build the project in VS, I get the error:
Error 1 SQL71501: Assembly: [DatabaseProject] has an unresolved reference to object [servername\User123].
...caused by:
CREATE ASSEMBLY [DatabaseProject] AUTHORIZATION [servername\User123]
FROM 0x4D5A90000300000004000000FFFF0000B8000etcetcetcetc
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
So, if in VS I add a create user script in the \Security folder:
CREATE USER [servername\User123] FOR LOGIN [servername\User123] WITH DEFAULT_SCHEMA = dbo
GO
GRANT CONNECT TO [servername\User123]
Then I can build the project.
However, if I then try to Publish the database, I get the error:
Creating [servername\User123]...
(47,1): SQL72014: .Net SqlClient Data Provider: Msg 15063, Level 16, State 1, Line 1 The login already has an account under a different user name.
(47,0): SQL72045: Script execution error. The executed script:
CREATE USER [servername\User123] FOR LOGIN [servername\User123];
An error occurred while the batch was being executed.
Is there a "right" way to do this?
This issue is due to a simple misunderstanding of how SQL Server handles the "owner" of the database as a database "principal". The concept of "database owner" shows up in two different ways:
As a database-level User having the name of dbo and a principal_id of 1. Now, what server-level Login maps to this particular User (i.e. "principal") is simply a matter of the value in the SID field in sys.database_principals:
SELECT sdp.*
FROM [sys].[database_principals] sdp
WHERE sdp.[principal_id] = 1;
This field will map to the SID field in sys.server_principals:
SELECT sdp.*, '---' AS [---], ssp.*
FROM [sys].[database_principals] sdp
INNER JOIN [sys].[server_principals] ssp
ON ssp.[sid] = sdp.[sid]
WHERE sdp.[principal_id] = 1;
Pay attention to the following fields in sys.database_principals:
type
type_desc
authentication_type
authentication_type_desc
Seeing as how your database is currently owned by a Windows Login, run the query immediately above (the 2nd query--the one with both tables). Next, change the database to be owned by sa. Next, open up a NEW query tab. Finally, run the same query in this new window (so that you can easily compare the "before" and "after" results), making sure to pay close attention to the 4 fields noted above, as well as the sid field. (Please note that it is possible to create Users without Logins and those will not show up, obviously, in a query that JOINs to sys.server_principals, but this question is dealing specifically with Logins).
From all of this you should see that specifying a Login to be the "owner" of a database does not, in fact, create a User for that Login: it merely updates the definition of the dbo User. Hence, the Login that owns the database does technically exist in that database, but always with the name of dbo instead of its actual name. This is why you are getting the following error:
The login already has an account under a different user name.
As a Database Role that any User in the database can be added to in order to be given those permissions.
To fix:
Remove your CREATE USER script from the \Security folder.
Use AUTHORIZATION [dbo] instead.
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.
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
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