Short version: Is it possible or not to use impersonation in ASP.NET to access mapped drives?
Long Version:
I'm currently using impersonation in ASP.NET to gain access to network files. This is working perfectly for any network file using a UNC path, but it is failing to access any files on mapped drives defined for the user account I'm impersonating.
For example, let's say a file lives on the network at \\machine\folder\file.txt
, and let's also say that drive S:
is mapped to \\machine\folder
. We need to be able to access both the full UNC path, \\machine\folder\file.txt
, as well as the shorter, mapped drive path, S:\file.txt
.
Obviously the standard ASP.NET process cannot access either.
Using a console application that runs under the local account with the mapped S:
drive, calling File.Exists(@"\\machine\folder\file.txt")
returns true, and File.Exists(@"S:\file.txt")
also returns true.
However, when impersonating in an ASP.NET context with the same local account, only File.Exists(@"\\machine\folder\file.txt")
returns true. File.Exists(@"S:\file.txt")
returns false.
I'm testing with IIS 7 running on my local Windows 7 Professional box, though this will need to run in both IIS 6 and IIS 7.
Impersonation is handled with a couple of classes in C# which I'll include here:
public static class Impersonation
{
private static WindowsImpersonationContext context;
public static void ImpersonateUser(string username, string password)
{
ImpersonateUser(".", username, password);
}
public static void ImpersonateUser(string domain, string username, string password)
{
StopImpersonating();
IntPtr userToken;
var returnValue = ImpersonationImports.LogonUser(username, domain, password,
ImpersonationImports.LOGON32_LOGON_INTERACTIVE,
ImpersonationImports.LOGON32_PROVIDER_DEFAULT,
out userToken);
context = WindowsIdentity.Impersonate(userToken);
}
public static void StopImpersonating()
{
if (context != null)
{
context.Undo();
context = null;
}
}
}
public static class ImpersonationImports
{
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_NETWORK = 3;
public const int LOGON32_LOGON_BATCH = 4;
public const int LOGON32_LOGON_SERVICE = 5;
public const int LOGON32_LOGON_UNLOCK = 7;
public const int LOGON32_LOGON_NETWORK_CLEARTEXT = 8;
public const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
public const int LOGON32_PROVIDER_DEFAULT = 0;
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int LogonUser(
string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
out IntPtr phToken
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int ImpersonateLoggedOnUser(
IntPtr hToken
);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int RevertToSelf();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr hObject);
}
Then, during Page_Load, we basically do something like this:
Impersonation.ImpersonateUser("DOMAIN", "username", "password");
if (!File.Exists(@"S:\file.txt"))
throw new WeCannotContinueException();
I realize using mapped drives isn't a best practice, but for legacy reasons it's desirable for our business. Is it possible or not to use impersonation in ASP.NET to access mapped drives?