Как поддержать проверку подлинности NTLM с резервной формой в ASP.NET MVC?

Как я могу реализовать следующее в приложении ASP.NET MVC:

  1. пользователь открывает интранет сайт
  2. пользователь молча аутентифицируется, если это возможно
  3. если аутентификация NTLM не сработала, покажите пользователю форму входа
  4. пользователь указывает логин и выбирает домен из списка предопределенных доменов
  5. пользователь аутентифицирован в коде с использованием AD

Я знаю, как реализовать 4 и 5, но не могу найти информацию о том, как объединить NTLM и формы. Так что диалоговое окно логина / пароля NTLM никогда не отображается - прозрачная аутентификация или приятная страница входа.

Как должно работать? Нужно ли пользователю спрашивать логин и пароль? Можно ли использовать ее текущие учетные данные (имя пользователя домена) без запроса ввода логина и пароля?

ОБНОВЛЕНИЕ для них, исследуя ту же проблему:

Когда я спрашивал об этом, я не до конца понимал, как внутренне работает аутентификация NTLM. Здесь важно понять, что если браузер пользователя не поддерживает должным образом NTLM или если поддержка NTLM отключена пользователем - у сервера никогда не будет возможности обойти это.

Как работает проверка подлинности Windows:

  1. Клиент отправляет обычный HTTP-запрос на сервер
  2. Сервер отвечает HTTP-статусом 401 и указывает, что для доступа к ресурсам должна использоваться аутентификация NTLM
  3. Клиент отправляет сообщение NTLM Type1
  4. Сервер отвечает NTLM Type2 сообщением с запросом
  5. Клиент отправляет сообщение типа 3 с ответом на вызов
  6. Сервер отвечает с фактическим запрошенным контентом

Как вы видите, браузер, не поддерживающий NTLM, не перейдет к шагу (3), вместо этого пользователю будет показана страница 401, сгенерированная IIS.

Если у пользователя нет учетных данных, после отмены всплывающего диалогового окна аутентификации NTLM браузер также не будет продолжать (3).

Поэтому у нас нет возможности автоматически перенаправлять пользователей на пользовательскую страницу входа.

Единственным вариантом здесь является наличие страницы "шлюза", на которой мы решаем, должен ли пользователь поддерживать NTLM и, если это так, перенаправить на домашнюю страницу, защищенную NTLM.

А если нет, покажите форму авторизации и разрешите аутентификацию, введя логин и пароль вручную.

Решение обычно принимается на основе IP-адреса пользователя и / или имени хоста либо путем сопоставления диапазонов IP-адресов, либо путем проверки таблицы предварительно определенных IP-адресов.

3 ответа

Решение

Эта статья может указать вам в правильном направлении. В основном у вас есть два приложения в двух виртуальных каталогах под одним именем хоста. Одно приложение использует проверку подлинности с помощью форм, другое - Windows. При использовании проверки подлинности Windows создается допустимый файл cookie проверки подлинности формы и перенаправляется во второй виртуальный каталог.

Аутентификация в смешанном режиме ASP.NET

У меня есть эта точная настройка на производстве, я настроил свой портал для использования FormsAuth и написал функцию, которая берет IP-адрес посетителей, чтобы найти учетную запись пользователя, который вошел на этот IP / ПК. Используя имя, которое я нахожу (например, DOMAIN\user), Я подтверждаю, что домен соответствует моему домену и что имя пользователя / учетная запись действительна в моем провайдере FormsAth, используя Membership.GetUser(<user>), Если этот вызов возвращает совпадение и пользователь IsApproved Я создаю FormsAuthenticationTicket & cookie для пользователя. У меня более 400 человек в сети, и это работает отлично, единственные компьютеры, которые все еще входят в систему (1. Пользователи без учетной записи на моем портале, 2. Несколько пользователей MAC/Linux, 3. Мобильные пользователи, которые не загружались в сети и чтобы групповая политика включила их брандмауэр в высокий уровень).

Подвох в этом решении заключается в том, что для запроса ПК пользователя требуется олицетворение учетной записи администратора домена и использование неуправляемого кода netapi32.dll.

Вот код, который я использую (для краткости внешние вызовы функций не предусмотрены). Я попытался немного упростить это, так как есть много внешних звонков.

string account = String.Empty;
string domain = String.Empty;
string user = String.Empty;


ImpersonateUser iu = new ImpersonateUser();  //Helper that Enabled Impersonation
if (iu.impersonateValidUser(StringHelper.GetAppSetting("DomainAccount"), StringHelper.GetAppSetting("DomainName"), StringHelper.GetEncryptedAppSetting("DomainAccountPassword")))
{
    NetWorkstationUserEnum nws = new NetWorkstationUserEnum(); //Wrapper for netapi32.dll (Tested on Vista, XP, Win2K, Win2K3, Win2K8)
    string host = nws.DNSLookup(Request.UserHostAddress); // netapi32.dll requires a host name, not an IP address

    string[] users = nws.ScanHost(host); // Gets the users/accounts logged in

    if (nws.ScanHost(host).Length > 0)
    {
        string workstationaccount = string.Empty;

        if (host.IndexOf('.') == -1)  // Pick which account to use, I have 99.9% success with this logic (only time doesn't work is when you run a interactive process as a admin e.g. Run As <process>).
        {
            workstationaccount = String.Format("{0}\\{1}$",StringHelper.GetAppSetting("DomainName"), host).ToUpper();
        }
        else
        {
            workstationaccount = String.Format("{0}\\{1}$", StringHelper.GetAppSetting("DomainName"), host.Substring(0, host.IndexOf('.'))).ToUpperInvariant();
        }

        account = users[users.Length - 1].Equals(workstationaccount) ? users[0] : users[users.Length - 1];

        domain = account.Substring(0, account.IndexOf("\\"));
        user = account.Substring(account.IndexOf("\\") + 1,
                                 account.Length - account.IndexOf("\\") - 1);
    }

    iu.undoImpersonation(); // Disable Impersonation
}

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

MembershipUser membershipUser = Membership.GetUser(user);

if (membershipUser != null && membershipUser.IsApproved)
{
    string userRoles = string.Empty;  // Get all their roles
    FormsAuthenticationUtil.RedirectFromLoginPage(user, userRoles, true); // Create FormsAuthTicket + Cookie + 
}

Я написал пост в блоге об этом давным-давно, здесь есть ссылка на обертку для netapi32.dll и мой помощник по подражанию, который я предоставил в посте Скачать исходный код

Вы не можете использовать NTLM и FormsAuthentication в одном приложении ASP.NET. Вам понадобятся два разных приложения в отдельных виртуальных каталогах.

Другие вопросы по тегам