Не удается пройти аутентификацию в ASP.NET Web Api с помощью HttpClient

У меня есть служба веб-API ASP.NET, которая работает на веб-сервере с включенной аутентификацией Windows.

У меня есть клиентский сайт, построенный на MVC4, который работает на другом сайте на том же веб-сервере, который использует HttpClient для извлечения данных из службы. Этот клиентский сайт работает с включенным олицетворением личности, а также использует проверку подлинности Windows.

Веб-сервер - Windows Server 2008 R2 с IIS 7.5.

Проблема, с которой я сталкиваюсь, - заставить HttpClient передать текущего пользователя Windows в рамках процесса аутентификации. Я настроил HttpClient следующим образом:

var clientHandler = new HttpClientHandler();
clientHandler.UseDefaultCredentials = true;
clientHandler.PreAuthenticate = true;
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
var httpClient = new HttpClient(clientHandler);

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

Этого не происходит. На самом деле, клиент, похоже, не проходит аутентификацию вообще.

Служба настроена на использование проверки подлинности Windows, и это, кажется, работает отлично. Я могу зайти на http://server/api/shippers в моем веб-браузере и получить запрос на аутентификацию Windows, после ввода я получаю запрошенные данные.

В журналах IIS я вижу, что запросы API принимаются без аутентификации и получают ответ на вызов 401.

Документация по этому вопросу, кажется, скудна.

Мне нужно некоторое понимание того, что может быть не так или другой способ использовать проверку подлинности Windows с этим приложением.

Спасибо, Крейг

4 ответа

Я исследовал исходный код HttpClientHandler (последняя версия, которую мне удалось достать), и это то, что можно найти в методе SendAsync:

// BeginGetResponse/BeginGetRequestStream have a lot of setup work to do before becoming async
// (proxy, dns, connection pooling, etc).  Run these on a separate thread.
// Do not provide a cancellation token; if this helper task could be canceled before starting then 
// nobody would complete the tcs.
Task.Factory.StartNew(startRequest, state);

Теперь, если вы проверите в своем коде значение SecurityContext.IsWindowsIdentityFlowSuppressed(), вы, скорее всего, получите значение true. В результате метод StartRequest выполняется в новом потоке с учетными данными процесса asp.net (не учетными данными олицетворенного пользователя).

Есть два возможных выхода из этого. Если у вас есть доступ к вашему серверу aspnet_config.config, вы должны установить следующие настройки (установка в web.config, похоже, не имеет никакого эффекта):

<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>

Если вы не можете изменить aspnet_config.config, вам придется создать свой собственный HttpClientHandler для поддержки этого сценария.

ОБНОВЛЕНИЕ ОТНОСИТЕЛЬНО ИСПОЛЬЗОВАНИЯ FQDN

Проблема, с которой вы столкнулись, - это функция в Windows, предназначенная для защиты от "отраженных атак". Чтобы обойти это, вам нужно добавить в белый список домен, к которому вы пытаетесь получить доступ на компьютере, который пытается получить доступ к серверу. Выполните следующие шаги:

  1. Перейти в Пуск -> Выполнить -> regedit
  2. разместить HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0 ключ реестра.
  3. Щелкните правой кнопкой мыши на нем, выберите New, а затем Multi-String Value.
  4. Тип BackConnectionHostNames (ENTER).
  5. Щелкните правой кнопкой мыши только что созданное значение и выберите " Изменить".
  6. Поместите имена хостов для сайтов, которые находятся на локальном компьютере, в поле значения и нажмите кнопку " ОК" (каждое имя хоста / полное доменное имя должно быть в отдельной строке, без подстановочных знаков, имя должно точно совпадать),
  7. Сохраните все и перезагрузите машину

Вы можете прочитать полную статью о проблеме здесь.

У меня тоже была такая же проблема. Благодаря исследованию, проведенному @tpeczek, я разработал следующее решение: вместо использования HttpClient (который создает потоки и отправляет запросы асинхронно), я использовал класс WebClient, который выдает запросы в том же потоке. Это позволяет мне передавать идентификационные данные пользователя в WebAPI из другого приложения ASP.NET.

Очевидным недостатком является то, что это не будет работать асинхронно.

var wi = (WindowsIdentity)HttpContext.User.Identity;

var wic = wi.Impersonate();
try
{
    var data = JsonConvert.SerializeObject(new
    {
        Property1 = 1,
        Property2 = "blah"
    });

    using (var client = new WebClient { UseDefaultCredentials = true })
    {
        client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
        client.UploadData("http://url/api/controller", "POST", Encoding.UTF8.GetBytes(data));
    }
}
catch (Exception exc)
{
    // handle exception
}
finally
{
    wic.Undo();
}

Примечание. Требуется пакет NuGet: Newtonsoft.Json, который использует тот же сериализатор JSON, который использует WebAPI.

Чтобы выдать себя за оригинального (аутентифицированного) пользователя, используйте следующую конфигурацию в файле Web.config:

<authentication mode="Windows" />
<identity impersonate="true" />

При такой конфигурации ASP.NET всегда олицетворяет аутентифицированного пользователя, и весь доступ к ресурсам выполняется с использованием контекста безопасности аутентифицированного пользователя.

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

Первый переход - это веб-сервер, в котором нет проблем с олицетворением аутентификации Windows. Но при использовании HttpClient или WebClient для проверки подлинности на другом сервере веб-сервер должен работать с учетной записью, которая имеет разрешение на необходимое делегирование.

Смотрите следующие подробности:
http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx

Исправить с помощью команды setspn:
http://www.phishthis.com/2009/10/24/how-to-configure-ad-sql-and-iis-for-two-hop-kerberos-authentication-2/(Вам потребуются достаточные права доступа к выполнить эти операции.)

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

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