Windows impersonation solves this problem by using the login details to acquire a user token. This token can then be used to obtain a WindowsIdentity, which is then used to generate an impersonation context. Within this context scope, you can then access the file system as the impersonated user.
Of course, you will need to store the user name and password for this approach to work.
First, define the Windows APIs required to obtain a user token from Windows:
internal class WindowsAPI
{
public const int LOGON32_PROVIDER_DEFAULT = 0;
public const int LOGON32_LOGON_INTERACTIVE = 2;
[DllImport( "advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode )]
public static extern bool LogonUser( String lpszUsername,
String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken
);
[DllImport( "kernel32.dll", CharSet = CharSet.Auto )]
public extern static bool CloseHandle( IntPtr handle );
}
Then, use these APIs to aquire a WindowsIdentity:
private WindowsIdentity GetIdentity( string userName, string password )
{
_userToken = IntPtr.Zero;
if ( !WindowsAPI.LogonUser(
userName,
AbbGrainDomain,
password,
WindowsAPI.LOGON32_LOGON_INTERACTIVE, WindowsAPI.LOGON32_PROVIDER_DEFAULT,
ref _userToken
) )
{
int errorCode = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception( errorCode );
}
return new WindowsIdentity( _userToken );
}
And finally, use this identity to generate an impersonation context:
public List<string> GetDirectories( string searchPath )
{
using ( WindowsImpersonationContext wic = GetIdentity().Impersonate() )
{
var directories = new List<string>();
var di = new DirectoryInfo( searchPath );
directories.AddRange( di.GetDirectories().Select( d => d.FullName ) );
return directories;
}
}
Finally it is important to clean up the windows handle using the IDisposable pattern, using the stored _userToken:
if ( _userToken != IntPtr.Zero )
WindowsAPI.CloseHandle( _userToken );