2013-03-25 12 views
10

Mam usługę WCF, która zawiera metodę Login, która sprawdza poprawność nazwy użytkownika i hasła względem danych logowania lokalnego komputera, a po pozornie losowym okresie przestanie działać dla niektórych użytkowników.Błąd podczas używania PrincipalContext.ValidateCredentials do uwierzytelnienia na komputerze lokalnym?

Rzeczywista komenda logowania wygląda następująco:

public UserModel Login(string username, string password, string ipAddress) 
{ 
    // Verify valid parameters 
    if (username == null || password == null) 
     return null; 

    try 
    { 
     using (var pContext = new PrincipalContext(ContextType.Machine)) 
     { 
      // Authenticate against local machine 
      if (pContext.ValidateCredentials(username, password)) 
      { 
       // Authenticate user against database 
       using (var context = new MyEntities(Connections.GetConnectionString())) 
       { 
        var user = (from u in context.Users 
           where u.LoginName.ToUpper() == username.ToUpper() 
             && u.IsActive == true 
             && (string.IsNullOrEmpty(u.AllowedIpAddresses) 
             || u.AllowedIpAddresses.Contains(ipAddress)) 
           select u).FirstOrDefault(); 

        // If user failed to authenticate against database 
        if (user == null) 
         return null; 

        // Map entity object to return object and assign session token 
        var userModel = Mapper.Map<User, UserModel>(user); 
        userModel.Token = Guid.NewGuid(); 
        userModel.LastActivity = DateTime.Now; 

        // Authenticated users are added to a list on the server 
        // and their login expires after 20 minutes of inactivity 
        authenticatedUsers.Add(userModel); 
        sessionTimer.Start(); 

        // User successfully authenticated, so return UserModel to client 
        return userModel; 
       } 
      } 
     } 
    } 
    catch(Exception ex) 
    { 
     // This is getting hit 
     MessageLog.WriteMessage(string.Format("Exception occurred while validating user: {0}\n{1}", ex.Message, ex.StackTrace)); 
     return null; 
    } 

    // If authentication against local machine failed, return null 
    return null; 
} 

To wydaje się działać dobrze na kilka dni, to będzie nagle przestać działać dla niektórych użytkowników i wyrzucić ten wyjątek:

Wielokrotne połączenia z serwerem lub udostępnionym zasobem tego samego użytkownika przy użyciu więcej niż jednej nazwy użytkownika są niedozwolone. Odłącz wszystkie poprzednie połączenia z serwerem lub udostępnionym zasobem i spróbuj ponownie. (Wyjątek od HRESULT: 0x800704C3)

na System.DirectoryServices.AccountManagement.CredentialValidator.BindSam (target String, nazwę użytkownika, hasło String String)

w System.DirectoryServices.AccountManagement.CredentialValidator.Validate (nazwę użytkownika String hasło String)

na System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials (String username, hasło String)

na MyNamespace.LoginService.Login (nazwa użytkownika ciąg znaków, hasło String, String ipAddress) w C: \ Users \ m e \ Pulpit \ somefolder \ LoginService.svc.cs: Linia 67

Linia 67 jest: if (pContext.ValidateCredentials(username, password))

Nie jestem pewien, czy to ma znaczenie, czy nie, ale ostateczna linia komunikatu o błędzie jest ścieżkę rozwiązania VS na mojej maszynie programistycznej, a nie ścieżkę do plików na serwerze produkcyjnym.

Po awarii nie działa tylko dla niektórych użytkowników, podczas gdy inni mogą kontynuować logowanie. Jedyne, co znalazłem, aby tymczasowo naprawić błąd, to iisreset. Zatrzymanie/uruchomienie strony internetowej lub recykling puli aplikacji nie działa.

Nie mogę odtworzyć błędu na żądanie. Próbowałem zalogować się do tego samego użytkownika z wielu sesji i adresów IP, logując się do różnych użytkowników z tej samej sesji przeglądarki w tym samym czasie, spamując przycisk Zaloguj, aby spróbować uruchomić go wielokrotnie, itd., Ale wszystko się pojawiło działać dobrze.

widzę z naszego rejestrowania że użytkownicy z powodzeniem w stanie zalogować się w przeszłości:

 
3/21/2013 
o 9:03a I logged in 
o 1:54p UserB logged in 
o 1:55p UserA logged in 
o 2:38p UserB logged in 
o 3:48p UserB logged in 
o 5:18p UserA logged in 
o 6:11p UserB logged in 

3/22/2013 
o 12:42p UserA logged in 
o 5:22p UserB logged in 
o 8:04p UserB logged in 

3/25/2013 (today) 
o 8:47a I logged in 
o 12:38p UserB tries logging in and fails. Repeated ~15 times over next 45 min 
o 1:58p I login successfully 
o 2:08p I try to login with UserB's login info and fail with the same error 

Powodem uwierzytelnić na lokalnej maszynie dlatego użytkownicy mają konta utworzone lokalnie na dostęp FTP, a nie chcieliśmy budować własnego niestandardowego systemu logowania ani zachęcać użytkowników do zapamiętania dwóch zestawów poświadczeń.

Kod powinien uwierzytelniać tylko poświadczenia użytkownika i nie powoduje żadnych innych czynności przy użyciu poświadczeń użytkownika. Nie ma innego kodu, który używa System.DirectoryServices, żadnego pliku IO, i nie ma dostępu do niczego lokalnie w systemie plików, poza plikami wymaganymi do uruchomienia aplikacji internetowej.

Co może spowodować pojawienie się tego błędu, pozornie losowego, po kilku dniach? I jak mogę to naprawić?

Serwer Windows Server 2003, który działa IIS 6.0 i jest skonfigurowany do korzystania .Net Framework 4.0

Odpowiedz

4

Najbliżej mogę znaleźć w Internecie w kierunku wyjaśnienia tego problemu jest this forum post, gdzie użytkownik doświadcza ten sam błąd i dostałem powtórkę stwierdzającą:

Dostawca WinNT nie działa dobrze w środowisku serwera. Jestem zaskoczony, że nie widzisz tego z dużo mniejszym obciążeniem. Mam udało mi się uzyskać to tylko z 2 lub 3 użytkownikami.

i this SO comment stwierdzając

Najlepszym sposobem, aby prawidłowo uwierzytelnić kogo jest użycie LogonUserAPI jak @stephbu pisać. Wszystkie inne metody opisane w tym poście nie będą PRACY 100%

gdzie „wszystkie inne metody” obejmuje górny głosowało odpowiedź korzystania PrincipalContext.ValidateCredentials

Its brzmiące jak PrincipalContext.ValidateCredentials nie jest całkowicie 100% wiarygodne na Windows Server 2003 i IIS6.0, więc przepisałem ponownie kod uwierzytelniający, aby zamiast tego użyć metodyWinAPI.

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

IntPtr hToken; 
if (LogonUser(username, "", password, 
    LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, out hToken)) 
{ 
    ... 
} 
+0

zmarnowałem kilka godzin, dzięki Rachel, –

Powiązane problemy