Question

I'm having trouble with a SQL DDL trigger for Create_User and I'm wondering if there is an issue with my syntax or something else I'm not seeing?

I have some tables in my database which are only available to a few users. The rest of the users in the database are not allowed to query these tables in any way. I've had no problems limiting current user permissions with

DENY SELECT, INSERT, UPDATE, DELETE ON dbo.SecretTable TO UserName

I'm trying to set up a DDL trigger to automatically run the Deny command when any new users are created. I am not the only one creating users in the database, so I won't be able to manually set permissions myself when new users are added.

With my trigger, I constantly receive the error

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

If I change the UserName placeholder to an already existing user in the trigger, I do not receive any errors - so it is not a permissions issue for my account. Here is my trigger:

CREATE TRIGGER [NewUserCreation]
ON DATABASE
After Create_User
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @x xml = EVENTDATA();   
    SELECT UserName = @x.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(max)');
    DENY SELECT, INSERT, UPDATE, DELETE, ON dbo.SecretTable TO [UserName]

END
GO

ENABLE TRIGGER [NewUserCreation] ON DATABASE
GO

Is there something I'm missing? The test results I've experienced so far seem to imply that the trigger is firing before the user account is actually created.

Was it helpful?

Solution

I think you'll have to use dynamic SQL for this. Something like

create TRIGGER [NewUserCreation] ON DATABASE 
After Create_User
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @x xml = EVENTDATA();   
    declare @UserName Varchar(30)
    SELECT @UserName = @x.value('(/EVENT_INSTANCE/ObjectName)[1]', 'varchar(max)');
    declare @Cmd nvarchar(100)
    set @cmd = 'DENY SELECT, INSERT, UPDATE, DELETE ON dbo.SecretTable TO ' + QUOTENAME(@UserName)
    exec sp_executesql @cmd
END
GO

ENABLE TRIGGER [NewUserCreation] ON DATABASE
GO

The reason your original code did not work is because your select username merely gave an alias UserName to the value returned from the select. You are not able to use that column alias in the DENY. Note that my example puts the value into a variable @UserName. Then, I build a dynamic DENY statement and externalize the value of @UserName which is concatenated to the DENY command.

You can see this in action with this code snippet. Assume I'm adding NewUser as a login and that is the value from the xml.

Declare @UserName varchar(100)
SELECT @UserName = (select 'NewUser')
declare @Cmd nvarchar(100)
set @cmd = 'DENY SELECT, INSERT, UPDATE, DELETE ON dbo.SecretTable TO ' + QUOTENAME(@UserName)
print @cmd

DENY SELECT, INSERT, UPDATE, DELETE ON dbo.SecretTable TO [NewUser]

Licensed under: CC-BY-SA with attribution
Not affiliated with dba.stackexchange
scroll top