К сожалению, я определил (анализируя эталонный исходный код WCF и помощь инструмента Fiddler для отслеживания сеансов HTTP), что это ошибка в стеке WCF.
Используя Fiddler, я заметил, что мойСлужба WCF вела себя не так, как любой другой веб-сайт, использующий обычную проверку подлинности.
Понятно, что это ДОЛЖНО произойти:
- Браузер отправляет
GET
запрос, не зная, чтопароль даже необходим. - Веб-сервер отклоняет запрос со статусом
401 Unauthorized
и включает в себя заголовок WWW-Authenticate
, содержащий информацию о допустимых методах аутентификации. - Браузер предлагает пользователю ввести учетные данные.
- Браузер отправляет запрос
GET
и включает соответствующий заголовок Authentication
с учетными данными. - Если учетные данные были правильными, веб-сервер отвечает
200 OK
и веб-страницей.Если учетные данные были неправильными, веб-сервер отвечает 401 Unauthorized
и включает в себя тот же заголовок WWW-Authenticate
, что и на шаге №2.
То, что в действительности происходило с моей службой WCF, было следующим:
- Браузер отправляет
GET
запрос, не зная, что пароль даже необходим. - WCF замечает, что в запросе нет заголовка
Authentication
, и слепо отклоняет запрос с 401 Unauthorized
статус и включает в себя WWW-Authenticate
заголовок.Пока все нормально. - Браузер запрашивает у пользователя учетные данные.Все еще в норме.
- Браузер повторно отправляет запрос
GET
, включая соответствующий заголовок Authentication
. - Если учетные данные были правильные, веб-сервер отвечает
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
согласно спецификации.