Consider this code:
ALTER TRIGGER [dbo].[AfterInsertUpdateTenant_Korisnici]
ON [dbo].[Korisnici]
WITH EXECUTE AS OWNER
FOR INSERT
AS
DECLARE @TenantId INT = dbo.GetCurrentTenantId();
EXECUTE AS LOGIN = 'sa';
UPDATE Korisnici
SET TenantId = @TenantId
FROM Inserted i
WHERE Korisnici.Id = i.Id;
REVERT;
On every table, there is a security policy that doesn't allow change of the TenantId
column on the table other than the one that is bound to the database user, but the policy will allow it for the "sa" user.
Problem is TenantId
, I need to get the TenantId
with the calling principal because TenantId
is bound to the database user. I know one solution: without with execute
in a trigger and calling a procedure that has with execute
after I get TenantId
and pass it into a procedure, but then I'd have to copy table Inserted into temp table so that I can access it in the procedure.
I would like better a solution where I can call execute as owner
later in object, after I get the TenantId
. Logically it's valid, but the question is; have they implemented it? execute as login = 'sa'
that you can see in the code is not a good solution because it requires that current login is able to impersonate the sa
login.
Point of this trigger is to allow a user not to specify TenantId
on an insert.
I don't have to even mention TenantId
in the application, everything is only on the SQL Server.
Another solution would be if the creator of an object could write some info on an object that I could read in security policy and based on that info allow the user to update the TenantId
. It may even be permissions on the object but the question is how can I read which object caused the call of the security policy?
I've figured out a solution where trigger calls the procedure that is in the schema forbidden to a user. The trigger has no "with execute" and can get TenantId and forward that info to the procedure. In the procedure, I have "with execute as owner" and is able to change records regarding any Tenant. Also, I am copying needed columns of the Inserted table into the temp table so that the procedure can see it, I don't see a way around that.
Even better solution:
alter trigger [dbo].[AfterInsertUpdateTenant_Korisnici]
on [dbo].[Korisnici]
with execute as owner
for insert
as
execute as user = original_login();
declare @TenantId int = dbo.GetCurrentTenantId();
revert;
update dbo.Korisnici
set TenantId = @TenantId
from Inserted i
where dbo.Korisnici.Id = i.Id;