I want to have a CLR function run as a specific windows identity when called from SQL Server Agent Jobs. To that end, the SQL statement calling the function has the form:
execute as user='domain\username'
select database.schema.function()
revert
The function itself, for arguments sake, could simply be something like:
[SqlFunction(DataAccess = DataAccessKind.Read)]
[return: SqlFacet(MaxSize = -1)]
public static SqlChars GetIdentityInformationImpersonated()
{
WindowsIdentity clientId;
WindowsImpersonationContext impersonatedUser;
string currentUser;
clientId = SqlContext.WindowsIdentity;
impersonatedUser = clientId.Impersonate();
currentUser = WindowsIdentity.GetCurrent().Name;
impersonatedUser.Undo();
return new SqlChars(currentUser);
}
This throws an exception:
A .NET Framework error occurred during execution of user-defined routine or aggregate "GetIdentityInformationImpersonated": System.NullReferenceException: Object reference not set to an instance of an object. System.NullReferenceException: at WinIdentityDebugging.IdentityResults.GetIdentityInformationImpersonated()
Which implies that the SqlContext.WindowsIdentity
is null. Now there are references across the internet claiming that such a thing is impossible, such as ...
Keep in mind that SQLCLR impersonation doesn't work with impersonated contexts (EXECUTE AS)
attempting to retrieve a SqlContext.WindowsIdentity object is an impersonated security context returns null currently and is doc'd to do so.
If the execution is happening in the context of an Execute As Login (statement directly or some module marked with it ) SqlContext.WindowsIdentity will be null unless the login is sysadmin. In this case SqlContext.WindowsIdentity will return the identity under which the server process is running.
But all of those references are quite old, and I cannot find any such restriction in the actual documentation. For example the SqlContext.WindowsIdentity page only refers to itself being null for SQL Auth callers:
A WindowsIdentity instance representing the Windows identity of the caller, or null if the client was authenticated using SQL Server Authentication.
So I'm hoping that there's a way to achieve this.
Is such a thing possible? Or am I out of luck?