11

Я создал самообслуживаемую службу WCF REST (с некоторыми дополнительными возможностями из Preview WCF REST Starter Kit Preview 2). Все это прекрасно работает.Самостоятельная служба WCF REST и базовая аутентификация

Теперь я пытаюсь добавить базовую аутентификацию в службу. Но я попадаю в довольно большие блокпосты в стеке WCF, что мешает мне это делать.

Оказывается, что HttpListener (которые используют самопринятый службы WCF внутри на низком уровне в стеке WCF) блокирует мои попытки вставить в WWW-Authenticate заголовок на самообразующейся 401 Unauthorized ответ. Зачем?

Я могу получить аутентификацию, если я забуду об этом WWW-Authenticate заголовке (что, похоже, и Microsoft). Но это проблема. Если я не отправлю обратно заголовок WWW-Authenticate, тогда веб-браузер не отобразит свой стандартный диалог входа в систему. Пользователь будет просто сталкиваться с страницей ошибок 401 Unauthorized без возможности входа в систему.

Услуги REST должны быть доступны как для компьютеров, так и для людей (как минимум, на уровне запроса GET). Поэтому я чувствую, что WCF REST не выполняет основную часть REST здесь. Кто-нибудь согласен со мной?

У кого есть обычная проверка подлинности, работающая с самообслуживанием службы WCF REST? Если да, то как вы это сделали?

PS: Очевидно, что мои намерения использовать небезопасную обычную проверку подлинности основаны на том, что я также получаю HTTPS/SSL для моего обслуживания. Но это другое дело.

PPS: Я пробовал WCF REST Contrib (http://wcfrestcontrib.codeplex.com/), и это имеет точно такую ​​же проблему. Похоже, что эта библиотека не была протестирована в сценариях с самообслуживанием.

Спасибо.

ответ

13

К сожалению, я определил (проанализировав исходный код ссылки WCF и помощь инструмента Fiddler для прослушивания сеанса HTTP), что это ошибка в стеке WCF.

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

Чтобы было ясно, это то, что должно произойти:

  1. браузер посылает запрос GET без каких-либо знаний о том, что пароль даже необходимо.
  2. Веб-сервер отклоняет запрос с состоянием 401 Unauthorized и включает заголовок WWW-Authenticate, содержащий информацию о приемлемых методах проверки подлинности.
  3. Браузер предлагает ввести учетные данные.
  4. Браузер отправляет GET запрос и включает соответствующий заголовок Authentication с полномочиями.
  5. Если учетные данные были верны, веб-сервер отвечает 200 OK и веб-страницей. Если учетные данные были неправильными, веб-сервер отвечает 401 Unauthorized и включает в себя тот же заголовок WWW-Authenticate, что и в Шаге 2.

Что на самом деле происходит с моей службы WCF был такой:

  1. браузер посылает запрос GET без каких-либо знаний о том, что пароль даже необходимо.
  2. WCF отмечает, что заголовок Authentication отсутствует в запросе и слепо отклоняет запрос с состоянием 401 Unauthorized и включает в себя заголовок WWW-Authenticate. Все нормально до сих пор.
  3. Браузер запрашивает у пользователя учетные данные. Все еще нормально.
  4. Браузер отправляет GET запрос, включая соответствующий заголовок Authentication.
  5. Если учетные данные были верны, веб-сервер отвечает 200 OK. Все хорошо. Если учетные данные были неверными, WCF отвечает 403 Forbidden и не содержит никаких дополнительных заголовков, таких как WWW-Authenticate.

Когда браузер получает статус 403 Forbidden, он не воспринимает это как неудачную попытку аутентификации. Этот код состояния предназначен для информирования браузера о том, что URL, к которому он пытался получить доступ, не работает. Это никак не связано с аутентификацией. Это страшная сторона влияет на то, что, когда пользователь неправильно вводит свое имя пользователя/пароль (а сервер отклоняется с помощью 403), веб-браузер не перепрофилирует пользователя для повторного ввода своих учетных данных. Фактически веб-браузер считает, что аутентификация прошла успешно, и поэтому сохраняет эти учетные данные для остальной части сеанса!

Имея это в виду, я хотел бы получить разъяснения:

RFC, 2617 (http://www.faqs.org/rfcs/rfc2617.html#ixzz0eboUfnrl) не упоминает где-либо использование кода 403 Forbidden статуса. В самом деле, что это на самом деле должно сказать по этому вопросу заключается в следующем:

Если исходный сервер не желает принять полномочия, отправленные с запросом, он должен вернуть (Несанкционированный) ответ 401 , Ответ ДОЛЖЕН содержать заголовок WWW-Authenticate , содержащий по меньшей мере одну ошибку (возможно, новую), применимую к запрашиваемому ресурсу.

WCF ни в одном из них. Он не правильно отправляет код состояния 401 Unauthorized. Он также не включает заголовок WWW-Authenticate.

Теперь найти дымящийся пистолет в пределах исходного кода WCF:

я обнаружил, что в HttpRequestContext классе является метод, называемый ProcessAuthentication, который содержит следующее (выдержка):

if (!authenticationSucceeded) 
{ 
    SendResponseAndClose(HttpStatusCode.Forbidden); 
} 

Я защищаю Microsoft много чего, но это невозможно.

К счастью, у меня это работает на «приемлемом» уровне. Это просто означает, что если пользователь случайно ошибочно вводит свое имя пользователя/пароль, единственный способ получить еще одну попытку - полностью закрыть свой веб-браузер и перезапустить его, чтобы повторить попытку.Все потому, что WCF не отвечает на неудачную попытку аутентификации с 401 Unauthorized и WWW-Authenticate заголовком согласно спецификации.

+0

Время переключиться на реальную инфраструктуру http, например openrasta :) – SerialSeb

+0

@serialseb У меня не было сердца, чтобы сказать ему, что я отказался от попыток решить проблемы с auth на WCF и сразу направился прямо к HttpListener. –

+0

Привет, ребята :) Даррел, я видел ваши комментарии в другом обсуждении и считаю, что я рассматривал это как вариант. К счастью, мы еще не инвестировали слишком много в WCF REST. Таким образом, мы можем пойти вперед и остановить его. – nbevans

6

Я нашел решение на основе link и this.

Во-первых, переопределить метод Validate в классе под названием CustomUserNameValidator которым наследует от System.IdentityModel.Selectors.UserNamePasswordValidator:

Imports System.IdentityModel.Selectors 
Imports System.ServiceModel 
Imports System.Net 

Public Class CustomUserNameValidator 
    Inherits UserNamePasswordValidator 

Public Overrides Sub Validate(userName As String, password As String) 
    If Nothing = userName OrElse Nothing = password Then 
     Throw New ArgumentNullException() 
    End If 

    If Not (userName = "user" AndAlso password = "password") Then 
     Dim exep As New AddressAccessDeniedException("Incorrect user or password") 
     exep.Data("HttpStatusCode") = HttpStatusCode.Unauthorized 
     Throw exep 
    End If 
End Sub 
End Class 

Весь фокус был изменить атрибут исключения «HttpStatusCode "в HttpStatusCode.Unauthorized

Второй создать serviceBehavior в App.config следующим образом:

<behaviors> 
    <endpointBehaviors> 
    <behavior name="HttpEnableBehavior"> 
     <webHttp /> 
    </behavior> 
    </endpointBehaviors> 
    <serviceBehaviors> 
    <behavior name="SimpleServiceBehavior"> 
     <serviceMetadata httpGetEnabled="true"/> 
     <serviceDebug includeExceptionDetailInFaults="false"/> 
     <serviceCredentials> 
     <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Service.CustomUserNameValidator, Service"/> 
     </serviceCredentials> 
    </behavior> 
    </serviceBehaviors> 
</behaviors> 

Наконец, мы должны указать конфигурацию для WebHttpBinding и применить его к конечной точке:

<bindings> 
    <webHttpBinding> 
    <binding name="basicAuthBinding"> 
     <security mode="TransportCredentialOnly"> 
     <transport clientCredentialType="Basic" realm=""/> 
     </security> 
    </binding> 
    </webHttpBinding> 
</bindings> 

<service behaviorConfiguration="SimpleServiceBehavior" name="Service.webService"> 
    <host> 
     <baseAddresses> 
     <add baseAddress="http://localhost:8000/webService" /> 
     </baseAddresses> 
    </host> 
    <endpoint address="http://localhost:8000/webService/restful" binding="webHttpBinding" bindingConfiguration="basicAuthBinding" contract="Service.IwebService" behaviorConfiguration="HttpEnableBehavior"/> 
</service> 
1

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

  1. Настройте свою самообслуживаемую службу, чтобы иметь сертификат SSL, привязанный к порту, на котором вы размещаете свою службу WCF. Это очень отличается от применения SSL-сертификата при использовании управляемого хостинга через нечто вроде IIS. Вы должны применить сертификат SSL с помощью утилиты командной строки. Вы не используете . НЕ используйте без использования, используя SSL, потому что учетные данные в заголовке не защищены. Вот (2) подробные сообщения, которые я написал на точно, как это сделать. Ваш вопрос является слишком большим, чтобы все детали в сообщении на форуме, так вот почему я обеспечиваю связей с всеобъемлющей деталью и пошаговыми инструкциями:

    Applying and Using a SSL Certificate With A Self-Hosted WCF Service

    Creating a WCF RESTful Service And Secure It Using HTTPS Over SSL

  2. Настройка вашего службы для использования обычной проверки подлинности. Это также многокомпонентное решение. 1st настраивает вашу службу для использования обычной проверки подлинности. Во-вторых, создать «customUserNamePasswordValidatorType» и проверить учетные данные на аутентифицировать клиента. Я вижу, что последнее сообщение не ускользнуло от этого, однако не использует HTTPS и составляет лишь 1 очень маленькую часть решения; будьте осторожны с руководством, которое делает не обеспечивает сквозное решение, включая конфигурацию и безопасность. Последним шагом является просмотр контекста безопасности для обеспечения авторизации на уровне метода, если это необходимо. В следующем сообщении, которое я написал, вы шаг за шагом о настройке, аутентификации, и авторизуете своих клиентов.

    RESTful Services: Authenticating Clients Using Basic Authentication

Это решение от конца до конца, необходимые для использования обычной проверки подлинности с самопринятый служб WCF.

Смежные вопросы