Search code examples
sql-serverpermissionstriggersauthenticationexecute-as

Switching execution context inside logon trigger


I have a database called MyDB in a Microsoft SQL Server 2008 Express instance using mixed mode authentication. The application using the database MyDB currently connects using Windows Authentication, using the current user's Windows credentials. This login is a member of the 'public' server role, and has a user mapped to it in the MyDB database. This database user is a member of the db_datareader and db_datawriter database roles.

What I would like is that when the application connects, it has permissions to read and write in MyDB. But when another application connects using the same login, it should only be allowed to read.

My thought was that I would create a logon trigger, which would check the application name part of the connection string, and based on that decide if the execution context should be switched. (For the record, I know that it is in no way secure to rely on the application name of the connection string, and that it is very easy to circumvent. The purpose here is not to secure the database, but to help users avoid changing data when they connect using another application, such as Microsoft Excel)

I have created a new login called 'myapp_reader' mapped to a user in the MyDB database, which is a member of db_datareader.

I then tried creating a logon trigger with the following TSQL:

CREATE TRIGGER CheckUser
ON ALL SERVER
AFTER LOGON AS
BEGIN
IF APP_NAME() <> 'My Application Name'
    BEGIN
        EXECUTE AS LOGIN = 'myapp_reader' WITH NO REVERT
    END
END

But unfortunately, it doesn't work. When I try to connect I get the following error:

Logon failed for login 'MyComputer\MyWindowsUsername' due to trigger execution.
Changed database context to 'master'.
Changed language setting to us_english. (Microsoft SQL Server, Error: 17892)

And when I look in the errorlog it says:

Error: 15590, Severity: 16, State: 1.
Can only use the 'No Revert' or 'Cookie' options with the 'Execute As' statement at the adhoc level.
Error: 17892, Severity: 20, State: 1.
Logon failed for login 'MyComputer\MyWindowsUsername' due to trigger execution. [CLIENT: xxx.xxx.xxx.xxx]

Does this error mean I cannot permanently change the execution context in the logon trigger?


Solution

  • I don't think its possible to change the execution context for the entire session. You could create a DML trigger for INSERT, UPDATE, and DELETE for every table/view in your database which does a rollback for a certain app_name(). You could write a procedure to automate the creation of all of these trigger.

    Alternatively, if you had the option of having applications such as Excel connecting via a linked server then you could change the execution context at this point. And create a logon trigger that rolls back the connection if users try connecting via Excel or other apps directly to the server.