Ошибка при использовании PrincipalContext.ValidateCredentials для аутентификации на локальном компьютере?

У меня есть служба WCF, которая содержит метод Login, который проверяет имя пользователя и пароль на учетные данные локального компьютера, и после кажущегося случайного периода времени он перестанет работать для некоторых пользователей.

Действительная команда входа выглядит следующим образом:

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

Кажется, что это работает отлично в течение нескольких дней, тогда он резко прекратит работу для некоторых пользователей и выбросит это исключение:

Не допускается несколько подключений к серверу или совместно используемому ресурсу одним и тем же пользователем, используя несколько имен пользователей. Отключите все предыдущие подключения к серверу или совместно используемому ресурсу и повторите попытку. (Исключение из HRESULT: 0x800704C3)

в System.DirectoryServices.AccountManagement.CredentialValidator.BindSam(String target, String userName, String password)

в System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)

в System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)

в MyNamespace.LoginService.Login(имя пользователя String, String password, String ipAddress) в папке C:\Users\me\Desktop\somefolder\LoginService.svc.cs: строка 67

Линия 67: if (pContext.ValidateCredentials(username, password))

Я не уверен, имеет значение это или нет, но последняя строка сообщения об ошибке - это путь решения VS на моей машине разработки, а не путь к файлам на рабочем сервере.

Когда он терпит неудачу, для некоторых пользователей он терпит неудачу, в то время как другие могут продолжать логин. Единственное, что я нашел для временного исправления ошибки, - это запустить iisreset. Остановка/запуск веб-сайта или переработка пула приложений не работают.

Я не могу воспроизвести ошибку по требованию. Я пробовал войти в систему с одним и тем же пользователем из нескольких сеансов и IP-адресов, одновременно вступая в систему с разными пользователями из одного сеанса браузера, рассылая спам кнопку "Войти", чтобы попытаться запустить ее несколько раз и т.д., Но все появляется чтобы нормально работать.

Из нашего ведения журнала видно, что пользователи успешно вошли в систему в прошлом:

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 login info and fail with the same error

Причина, по которой мы аутентифицируемся на локальном компьютере, заключается в том, что у пользователей есть учетная запись, созданная локально для доступа к FTP, и мы не хотим создавать собственную систему входа в систему или заставляем наших пользователей помнить два набора учетных данных.

Код должен только аутентифицировать учетные данные пользователя и не выполняет ничего другого с учетными данными пользователя. Нет другого кода, который использует System.DirectoryServices, не будет запускаться IO файла и не будет доступа к чему-либо локально в файловой системе, кроме файлов, необходимых для запуска веб-приложения.

Что может вызвать появление этой ошибки, казалось бы, случайным образом через несколько дней? И как я могу это исправить?

Сервер - это Windows Server 2003, который запускает IIS 6.0, и он настроен на использование .Net Framework 4.0

Ответ 1

Ближайший, который я могу найти в Интернете, чтобы объяснить эту проблему, - этот пост форума, где пользователь испытывает ту же ошибку и получил повторную запись

Поставщик WinNT не работает в серверной среде. я на самом деле удивителен, вы не видите этого с гораздо меньшей нагрузкой. у меня есть смог получить это только у 2 или 3 пользователей.

и этот комментарий СОСТОЯНИЯ, указав

Лучший способ правильно идентифицировать кого-то - использовать LogonUserAPI как пишет @stephbu. Все другие методы, описанные в этом сообщении, НЕ РАБОТА 100%

где "все другие методы" включают верхний проголосовавший ответ на использование PrincipalContext.ValidateCredentials

Его звучание как PrincipalContext.ValidateCredentials не полностью на 100% надежное в Windows Server 2003 и IIS6.0, поэтому я переписал код аутентификации, чтобы использовать LogonUser вместо WinAPI.

[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))
{
    ...
}