2013-03-25 15 views
10

Ich habe einen WCF-Dienst, der eine Login-Methode enthält, die einen Benutzernamen und ein Kennwort für die Anmeldeinformationen des lokalen Computers überprüft und nach einer scheinbar zufälligen Zeit für einige Benutzer nicht mehr funktioniert.Fehler bei der Verwendung von PrincipalContext.ValidateCredentials zur Authentifizierung gegen einen lokalen Computer?

Der eigentliche Login Befehl sieht wie folgt aus:

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

Dies scheint für ein paar Tage gut zu funktionieren, dann wird es plötzlich für einige Benutzer aufhören zu arbeiten und werfen diese Ausnahme:

Mehrere Verbindungen zu einem Server oder einer freigegebenen Ressource durch denselben Benutzer mit mehr als einem Benutzernamen sind nicht zulässig. Trennen Sie alle vorherigen Verbindungen zum Server oder zur freigegebenen Ressource und versuchen Sie es erneut. (Ausnahme von HRESULT: 0x800704C3)

bei System.DirectoryServices.AccountManagement.CredentialValidator.BindSam (String Ziel, String Benutzername, Passwort String)

bei System.DirectoryServices.AccountManagement.CredentialValidator.Validate (String USERNAME- String Passwort)

bei System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials (String Benutzername, Passwort-String)

bei MyNamespace.LoginService.Login (String Benutzername, Passwort-String, String ipAddress) in C: \ Benutzer \ m e \ Desktop \ somefolder \ LoginService.svc.cs: Linie 67

Linie 67 ist: if (pContext.ValidateCredentials(username, password))

Ich bin nicht sicher, wenn es darauf ankommt oder nicht, aber die letzte Zeile der Fehlermeldung ist die Pfad der VS-Lösung auf meinem Entwicklungscomputer, nicht der Pfad zu den Dateien auf dem Produktionsserver.

Wenn es fehlschlägt, schlägt es nur für einige Benutzer fehl, während andere weiterhin gut einloggen können. Das einzige, was ich gefunden habe, um den Fehler vorübergehend zu beheben, läuft iisreset. Das Stoppen/Starten der Website oder das Recycling des App-Pools funktioniert nicht.

Ich kann den Fehler bei Bedarf nicht reproduzieren. Ich habe versucht, mich mit demselben Benutzer aus mehreren Sitzungen und IP-Adressen anzumelden, mich gleichzeitig mit verschiedenen Benutzern aus derselben Browsersitzung anzumelden, die Login-Schaltfläche zu spammen und zu versuchen, sie mehrfach auszuführen usw., aber alles erscheint um gut zu arbeiten.

Ich kann aus unserer Protokollierung sehen, dass die Nutzer erfolgreich in der Lage gewesen, in der Vergangenheit einloggen:

 
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 

Der Grund, warum wir gegen den lokalen Rechner authentifizieren ist, weil die Benutzer ein Konto lokal für die FTP-Zugang erstellt und Wir wollten kein eigenes benutzerdefiniertes Anmeldesystem erstellen oder unsere Benutzer sich an zwei Gruppen von Anmeldeinformationen erinnern.

Der Code sollte nur die Anmeldeinformationen des Benutzers authentifizieren und tut nichts anderes mit den Anmeldeinformationen des Benutzers. Es gibt keinen anderen Code, der System.DirectoryServices verwendet, keine Datei-IO und keinen Zugriff auf irgendetwas im Dateisystem außer den Dateien, die zum Ausführen der Webanwendung erforderlich sind.

Was kann dazu führen, dass dieser Fehler nach einigen Tagen scheinbar zufällig auftritt? Und wie kann ich es reparieren?

Der Server ist Windows Server 2003, der IIS 6.0 ausgeführt wird, und es ist Setup .Net Framework 4.0 verwenden

Antwort

4

Die nächstgelegene ich online zur Erklärung dieses Problem this forum post gibt, in dem der Benutzer den gleichen Fehler auftreten und bekam eine Wiederholung:

Der WinNT-Anbieter ist nicht gut in einer Serverumgebung. Ich bin eigentlich überrascht, Sie sehen dies nicht mit einer viel kleineren Last. Ich habe war in der Lage, dies mit nur 2 oder 3 Benutzern zu bekommen.

und this SO comment

Der beste Weg, die besagt, jemanden richtig zu authentifizieren ist LogonUserAPI zu verwenden, wie @stephbu zu schreiben. Alle anderen in diesem Beitrag beschriebenen Methoden nicht WORK 100%

wo „alle anderen Methoden“ die Top-Antwort des Verwendens PrincipalContext.ValidateCredentials

Es ist wie PrincipalContext.ValidateCredentials klingen gestimmt enthält, ist nicht ganz 100% zuverlässig auf Windows Server 2003 und IIS6.0, also habe ich meinen Authentifizierungscode umgeschrieben, um stattdessen die WinAPI-Methode LogonUser zu verwenden.

[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

ich verschwendete mehrere Stunden, danke Rachel, –