Hacerse pasar por un usuario de Windows

Estoy usando el código para suplantar una cuenta de usuario para tener acceso a un recurso compartido de archivos.

public class Impersonator : IDisposable { #region Public methods. // ------------------------------------------------------------------ ///  /// Constructor. Starts the impersonation with the given credentials. /// Please note that the account that instantiates the Impersonator class /// needs to have the 'Act as part of operating system' privilege set. ///  /// The name of the user to act as. /// The domain name of the user to act as. /// The password of the user to act as. public Impersonator( string userName, string domainName, string password ) { ImpersonateValidUser( userName, domainName, password ); } // ------------------------------------------------------------------ #endregion #region IDisposable member. // ------------------------------------------------------------------ public void Dispose() { UndoImpersonation(); } // ------------------------------------------------------------------ #endregion #region P/Invoke. // ------------------------------------------------------------------ [DllImport("advapi32.dll", SetLastError=true)] private static extern int LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern int DuplicateToken( IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] private static extern bool CloseHandle( IntPtr handle); private const int LOGON32_LOGON_INTERACTIVE = 2; private const int LOGON32_PROVIDER_DEFAULT = 0; // ------------------------------------------------------------------ #endregion #region Private member. // ------------------------------------------------------------------ ///  /// Does the actual impersonation. ///  /// The name of the user to act as. /// The domain name of the user to act as. /// The password of the user to act as. private void ImpersonateValidUser( string userName, string domain, string password ) { WindowsIdentity tempWindowsIdentity = null; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; try { if ( RevertToSelf() ) { if ( LogonUser( userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token ) != 0 ) { if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 ) { tempWindowsIdentity = new WindowsIdentity( tokenDuplicate ); impersonationContext = tempWindowsIdentity.Impersonate(); } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } finally { if ( token!= IntPtr.Zero ) { CloseHandle( token ); } if ( tokenDuplicate!=IntPtr.Zero ) { CloseHandle( tokenDuplicate ); } } } ///  /// Reverts the impersonation. ///  private void UndoImpersonation() { if ( impersonationContext!=null ) { impersonationContext.Undo(); } } private WindowsImpersonationContext impersonationContext = null; // ------------------------------------------------------------------ #endregion } 

Luego usando:

 using (new Impersonator("username", "domain", "password")) { Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); } 

Aparece un error de “Acceso denegado”.

Este usuario supuestamente tiene acceso a este recurso compartido. Puedo mapear un disco, uso “net use” pero este código no funcionará. Ahora estoy pensando que es el código. ¿Alguien ve algo? ¿Hay una mejor manera de hacer esto?

prueba esto :

 [DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser( string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); 

Uso:

 IntPtr userToken = IntPtr.Zero; bool success = External.LogonUser( "john.doe", "domain.com", "MyPassword", (int) AdvApi32Utility.LogonType.LOGON32_LOGON_INTERACTIVE, //2 (int) AdvApi32Utility.LogonProvider.LOGON32_PROVIDER_DEFAULT, //0 out userToken); if (!success) { throw new SecurityException("Logon user failed"); } using (WindowsIdentity.Impersonate(userToken)) { Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); } 

Si estoy entendiendo correctamente, tu intención es ejecutar el proceso en el contexto de suplantación.

El documento de CreateProcess (que utiliza Process.Start) dice: si el proceso de llamada se está haciendo pasar por otro usuario, el nuevo proceso usa el token para el proceso de llamada, no el token de suplantación. Para ejecutar el nuevo proceso en el contexto de seguridad del usuario representado por el token de suplantación, use la función CreateProcessAsUser o CreateProcessWithLogonW.

Entonces, estás usando la API incorrecta para hacer eso.

En lugar de usar su clase Impersonator , ¿qué sucede cuando llama a Process.Start y pasa en una instancia de ProcessStartInfo que contiene el nombre de usuario, la contraseña y el dominio donde desea ejecutar el proceso?

Quizás, si eso funciona, entonces su clase Impersonator debería crear una instancia de ProcessStartInfo y usarla para crear nuevos procesos (encapsular eso dentro de la misma clase).

 var psi = new ProcessStartInfo("explorer.exe", @"/root,\\server01-Prod\abc"); psi.Domain = domain; psi.UserName = username; psi.Password = password; psi.WorkingDirectory = workingDir; Process.Start(psi); 

Además, según los documentos de MSDN …

Establecer las propiedades de dominio, nombre de usuario y contraseña en un objeto ProcessStartInfo es la práctica recomendada para iniciar un proceso con credenciales de usuario.

También debe establecer el directorio de trabajo al iniciar un proceso con diferentes credenciales de usuario.