2014-12-02 24 views
5

Próbuję przetestować aplikację sieci Web ASP.NET MVC4 łączącą się z różnymi użytkownikami w tym samym czasie przy użyciu podszywania się pod inny numer. Tak więc pomysłem na test było wykonanie kilku instancji sterownika, każdy z innym podszytym użytkownikiem. Brzmi to konceptualnie łatwo ...IEDriverServer podnosi błąd podczas podszywania się pod numer

Jeśli jednak po wywołaniu LogonUser z innego użytkownika niż bieżący, uruchamiasz IEDriverServer, okno dialogowe błędu aplikacji jest wyświetlane, gdy jest uruchamiane. Jest to informacja zarejestrowana w dzienniku zdarzeń:

Faulting application name: IEDriverServer.exe, version: 2.44.0.0, time stamp: 0x54496690 
Faulting module name: IED7543.tmp, version: 0.0.0.0, time stamp: 0x5449668c 
Exception code: 0xc0000005 
Fault offset: 0x000000000009d609 
Faulting process id: 0x760 
Faulting application start time: 0x01d00e3d12f93475 
Faulting application path: ...\bin\IEDriverServer.exe 
Faulting module path: C:\Users\user\AppData\Local\Temp\IED7543.tmp 
Report Id: 5383a54d-7a30-11e4-b39c-000c29b46927 

Oto kod, którego używam do podszywania się. Opiera się ona na wszystkich przykładów znalazłem, więc nie ma niespodzianek ... Próbowaliśmy także do użył SimpleImpersonation packege z takim samym skutkiem:

public class ImpersonationHelper 
{ 
    public enum LogonType 
    { 
     Interactive = 2, 
     Network = 3, 
     Batch = 4, 
     Service = 5, 
     Unlock = 7, 
     Cleartext = 8, // Win2K or higher 
     NewCredentials = 9 // Win2K or higher 
    }; 

    public enum LogonProvider 
    { 
     Default = 0, 
     Winnt35 = 1, 
     Winnt40 = 2, 
     Winnt50 = 3 
    }; 

    public enum ImpersonationLevel 
    { 
     SecurityAnonymous = 0, 
     SecurityIdentification = 1, 
     SecurityImpersonation = 2, 
     SecurityDelegation = 3 
    } 

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

    [DllImport("kernel32.dll")] 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
    [SuppressUnmanagedCodeSecurity] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool CloseHandle(IntPtr handle); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern int DuplicateToken(IntPtr hToken, 
     int impersonationLevel, ref IntPtr hNewToken); 

    public sealed class Impersonator : IDisposable 
    { 
     public string Domain { get; private set; } 
     public string User { get; private set; } 
     public string Password { get; private set; } 
     public LogonType Type { get; private set; } 
     public LogonProvider Provider { get; private set; } 

     private WindowsImpersonationContext _context; 
     private IntPtr _token; 

     [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] 
     public Impersonator(string domain, string user, string password, 
      LogonType type = LogonType.Interactive, 
      LogonProvider provider = LogonProvider.Default) 
     { 
      Domain = domain; 
      User = user; 
      Password = password; 
      Type = type; 
      Provider = provider; 
      _token = IntPtr.Zero; 

      Logon(); 
     } 

     public void Dispose() 
     { 
      Undo(); 
     } 

     private void Logon() 
     { 
      try 
      { 
       if (!LogonUser(User, Domain, Password, (int)Type, (int)Provider, out _token)) 
       { 
        int ret = Marshal.GetLastWin32Error(); 
        throw new Exception(String.Format("LogonUser failed with error code : {0}", ret)); 
       } 

       _context = WindowsIdentity.Impersonate(_token); 
      } 
      catch (Exception exception) 
      { 
       var message = exception.Message; 
       Undo(); 
      } 
     } 

     private void Undo() 
     { 
      try 
      { 
       if (_token != IntPtr.Zero) 
       { 
        CloseHandle(_token); 
        _token = IntPtr.Zero; // Clean _token so Undo() could be called several times 
       } 

       if (_context != null) 
       { 
        _context.Undo(); 
        _context = null; // Clean _context so Undo() could be called several times 
       } 
      } 
      catch (Exception exception) 
      { 
       var message = exception.Message; 
       // Releasing resources failed... 
      } 
     } 
    } 
} 

kod, który wywołuje wyjątek stanowi:

using (new ImpersonationHelper.Impersonator("WIN-NKLTTMMUEPD", "tester", "tester")) 
{ 
    using (IWebDriver driver = new InternetExplorerDriver()) 
    { 
     driver.Url = _appAddress; 
     return null; 
    } 
} 

Czy ktoś wie, w jaki sposób mogę zapobiec występowaniu tego błędu? Z góry bardzo dziękuję.

Odpowiedz

2

Nie udało się odtworzyć awarii Twojego IEDriver.

Jednak, jak określiłeś nagrodę za to pytanie, nie miałem nic przeciwko spędzaniu czasu na szukaniu rozwiązania. Nigdy nie zaimplementowałem Uwierzytelniania Windows ani nie potrzebowałem do testowania podszywania się przedtem, jednak mam doświadczenie z testami automatyzacji interfejsu użytkownika.

Time-box do godziny:

  • stworzył przykładową aplikację Intranet MVC, który używa uwierzytelniania systemu Windows;
  • dodano nowy projekt i ustawiono podstawowy test jednostki, który wczytuje witrynę.
  • dodano podszywanie się.

Nie jestem pewien, jak dokładnie zostały zaimplementowane testy, jednak projekty .NET/MVC Gorąco polecam korzystanie z Seleno. Jest to otok wokół sterownika sieci Web Selenium (aktualnie używanego), jednak sprawia, że ​​testowanie interfejsu użytkownika staje się mniej bolesne/kruche, wymuszając konwencję implementacji obiektów stron i komponentów strony oraz odczytu i zapisu danych strony internetowej przy użyciu silnie typowanych modeli widoku.

Polecam również używanie biblioteki SimpleImpersonation, ponieważ jest to bezpieczniejsza/czystsza implementacja funkcji Win32 API LogonUser, np. używa SafeHandle, a utylizacja ścieżki jest czystsza.

Test że napisałem,

[Test] 
public void GivenImpersonatedUser_IsLoggedInCorrectly() 
{ 
    const string domain = "domain"; // . for local machine 
    const string username = "impersonate.username"; 
    const string password = "[email protected]"; 

    const LogonType logonType = LogonType.Interactive; 

    using (Impersonation.LogonUser(domain, username, password, logonType)) 
    { 
     var page = Host.Instance.NavigateToInitialPage<HomePage>(); 
     Assert.That(page.LoginPanel.LoggedInUserName, Is.EqualTo(string.Format("{0}\\{1}", domain, username))); 
    } 
} 

Jest to obiekt Seleno Page, nazwany HomePage, który korzysta z elementem wielokrotnego użytku LoginPanel.

public class HomePage : Page 
{ 
    public LoginPanel LoginPanel 
    { 
     get { return GetComponent<LoginPanel>(); } 
    } 
} 

public class LoginPanel : UiComponent 
{ 

    public string LoggedInUserName 
    { 
     get { return Find.Element(By.Id("login-username")).Text; } 
    } 
} 

Konfiguracja hosta Seleno, przy użyciu IEDriver.

public static class Host 
{ 
    private static readonly InternetExplorerDriver Driver = new InternetExplorerDriver(); 

    public static readonly SelenoHost Instance = new SelenoHost(); 

    static Host() 
    { 
     Instance.Run(c => 
     { 
      c.WithRemoteWebDriver(() => Driver); 
      c.ProjectToTest(new WebApplication(ProjectLocation.FromFolder("WebApplication1"), 61285)); 

      c.UsingLoggerFactory(new ConsoleFactory()); 
      c.UsingCamera("C:\\screenshots"); 
     }); 
    } 
     var codeBase = assembly.CodeBase; 
     var uri = new UriBuilder(codeBase); 
     var path = Uri.UnescapeDataString(uri.Path); 

     return Path.GetDirectoryName(path); 
    } 

} 

kilka innych rzeczy nauczyłem: - Dostaniesz kod błędu 1326 jeżeli nazwa użytkownika lub hasło jest nieprawidłowe. - Możesz użyć Process Hacker, aby potwierdzić, że proces Webdriver został uruchomiony przy użyciu prawidłowego tokena uwierzytelniania.

Jak już powiedziałem, nie byłem w stanie odpowiedzieć na dokładny problem, jednak spróbuj użyć powyższego i skomentuj z powrotem - z przyjemnością pomożemy.

+1

Twoja odpowiedź zawiera wiele cennych informacji, które pozwolą Ci przeprowadzić testy obejmujące kilku użytkowników. Dzięki za twój wysiłek! Błąd okazał się jednak problemem w przypadku wersji x64 sterownika. – yeyeyerman

+0

Przepraszam, że nie mogłem rozwiązać Twojego problemu. – Dennis