Impersonare un utente Windows

Sto usando il codice per impersonare un account utente per ottenere l’accesso a una condivisione di file.

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 } 

Quindi usando:

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

Ottengo un errore “Accesso negato”.

Questo utente ha supposamente accesso a questa condivisione. Posso mappare un’unità, usare “net use” ma questo codice non funzionerà. Ora penso che sia il codice. Qualcuno vede qualcosa? C’è un modo migliore per farlo?

prova questo :

 [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"); } 

Se sto capendo correttamente, la tua intenzione è quella di eseguire il processo nel contesto di rappresentazione.

Il documento di CreateProcess (che viene utilizzato da Process.Start) dice: Se il processo chiamante sta impersonando un altro utente, il nuovo processo utilizza il token per il processo chiamante, non il token di rappresentazione. Per eseguire il nuovo processo nel contesto di sicurezza dell’utente rappresentato dal token di rappresentazione, utilizzare la funzione CreateProcessAsUser o CreateProcessWithLogonW.

Quindi, stai usando l’API sbagliata per farlo.

Invece di usare la tua class Impersonator , cosa succede quando chiami Process.Start e passi in un’istanza ProcessStartInfo che contiene nome utente, password e dominio su cui vuoi eseguire il processo?

Forse, se funziona, la class Impersonator dovrebbe creare un’istanza ProcessStartInfo e usarla per creare nuovi processi (incapsulati all’interno della class stessa).

 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); 

Inoltre, secondo i documenti MSDN …

L’impostazione delle proprietà Dominio, Nome utente e Password in un object ProcessStartInfo è la pratica consigliata per avviare un processo con le credenziali dell’utente.

È inoltre necessario impostare la directory di lavoro quando si avvia un processo con credenziali utente diverse.