I have an application that needs to do a lot of impersonation, due to moving and creating many files across protected network shares. I've created a simple static class that has a method takes a user, domain, password and a delegate that contains code you need run under the impersonation context.
The problem I've been running into is when the CLR tries to bind to a referenced assembly under this context. A FileLoadException is thrown with an 'Access is denied' message.
I'm led to believe that this is due to the impersonated user not having sufficient privileges to the *.DLL file under the filesystem. For example, I can write benign code just before the impersonation block, which accomplishes nothing other than to load types from the problem assembly before the context switches to the impersonated user, and this works great! However I don't really consider this to be an elegant solution – am I going to need to begin worrying about what types I can use under impersonation, making sure I put random typeof()
statements beforehand?
What makes this more frustrating is that I don't run into this problem on my local development machine. It's when the assemblies get shipped off to the beta environment does this problem occur. And I don't have access to read the file permissions from the beta environment to try and mimic them on my location machine.
In any case, I tried this solution:
// Defined above:
// System.Security.Principal.WindowsIdentity identity;
// System.Security.Principal.WindowsImpersonationContext context;
context = identity.Impersonate();
int tries = 0;
while ( true )
{
try
{
contextAction();
}
catch ( FileLoadException ex )
{
if ( tries > MAX_TRIES )
{
// don't allow an infinite loop
throw;
}
if ( String.IsNullOrEmpty( ex.FileName ) )
{
// if this is null/empty, we can't really recover
throw;
}
context.Undo(); // return to current logon
try
{
var assemblyName = new AssemblyName( ex.FileName );
Assembly.Load( assemblyName );
tries++;
continue;
}
finally
{
context = identity.Impersonate(); // re-impersonate
}
}
finally
{
// return to your current windows logon
context.Undo();
}
}
No dice. I still get the 'Access is denied' exception, except now from the line starting with Assembly.Load
.
One interesting thing to note is I was getting the same exception from the build server. This above solution fixed it on the build server. Not in our beta environment.
What am I missing here? Thanks.