[foundation] Fix 401s in the NSUrlSessionHandler. Fixes #42936 (#970)

The NSUrlSessionHandler is not dealing with 40s correctly, unfortunatly
we are modifying the Authorization header which is a reserved header as
per apple documentation. We need to hide this issue by dealing with the
challenge in the handler.

The fix checks if it is the very first failure of the challenge and we
do have the header, in that case, reject the request and continue with
the handler execution.

Fixes bug https://bugzilla.xamarin.com/show_bug.cgi?id=42936
This commit is contained in:
Manuel de la Pena 2016-10-11 19:06:06 +02:00 коммит произвёл Sebastien Pouliot
Родитель a4784b3866
Коммит 0d95c6846c
1 изменённых файлов: 22 добавлений и 1 удалений

Просмотреть файл

@ -321,8 +321,29 @@ namespace Foundation {
completionHandler (sessionHandler.AllowAutoRedirect ? newRequest : null);
}
public override void DidReceiveChallenge(NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
public override void DidReceiveChallenge (NSUrlSession session, NSUrlSessionTask task, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
// case for the basic auth failing up front. As per apple documentation:
// The URL Loading System is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers using
// the addValue(_:forHTTPHeaderField:) or setValue(_:forHTTPHeaderField:) methods:
// Authorization
// Connection
// Host
// Proxy-Authenticate
// Proxy-Authorization
// WWW-Authenticate
// but we are hiding such a situation from our users, we can nevertheless know if the header was added and deal with it. The idea is as follows,
// check if we are in the first attempt, if we are (PreviousFailureCount == 0), we check the headers of the request and if we do have the Auth
// header, it means that we do not have the correct credentials, in any other case just do what it is expected.
if (challenge.PreviousFailureCount == 0) {
var authHeader = GetInflightData (task).Request.Headers.Authorization;
if (!(string.IsNullOrEmpty (authHeader.Scheme) && string.IsNullOrEmpty (authHeader.Parameter))) {
completionHandler (NSUrlSessionAuthChallengeDisposition.RejectProtectionSpace, null);
return;
}
}
if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodNTLM) {
if (sessionHandler.Credentials != null) {
var credentialsToUse = sessionHandler.Credentials as NetworkCredential;