К сожалению, я определил (анализируя исходный код ссылки 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 в соответствии со спецификацией.
person
nbevans
schedule
04.02.2010