Esempio n. 1
0
        /// <summary>
        /// Keeps sending requests until a response code that doesn't require authentication happens or if
        /// the request requires authentication and the user has stopped trying to enter them (i.e. they hit cancel when they are prompted).
        /// </summary>
        internal static WebResponse GetResponse(Func<WebRequest> createRequest,
                                                Action<WebRequest> prepareRequest,
                                                IProxyCache proxyCache,
                                                ICredentialCache credentialCache,
                                                ICredentialProvider credentialProvider)
        {
            IHttpWebResponse previousResponse = null;
            HttpStatusCode? previousStatusCode = null;
            bool usingSTSAuth = false;
            bool continueIfFailed = true;
            int proxyCredentialsRetryCount = 0;
            int credentialsRetryCount = 0;

            while (true)
            {
                // Create the request
                var request = (HttpWebRequest)createRequest();
                request.Proxy = proxyCache.GetProxy(request.RequestUri);
                if (request.Proxy != null && request.Proxy.Credentials == null)
                {
                    request.Proxy.Credentials = CredentialCache.DefaultCredentials;
                }

                if (previousResponse == null)
                {
                    // Try to use the cached credentials (if any, for the first request)
                    request.Credentials = credentialCache.GetCredentials(request.RequestUri);

                    // If there are no cached credentials, use the default ones
                    if (request.Credentials == null)
                    {
                        request.UseDefaultCredentials = true;
                    }
                }
                else if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                {
                    request.Proxy.Credentials = credentialProvider.GetCredentials(request, CredentialType.ProxyCredentials, retrying: proxyCredentialsRetryCount > 0);

                    continueIfFailed = request.Proxy.Credentials != null;

                    proxyCredentialsRetryCount++;
                }
                else if ((previousStatusCode == HttpStatusCode.Unauthorized) && !usingSTSAuth)
                {
                    // If we are using STS, the auth's being performed by a request header. We do not need to ask the user for credentials at this point.
                    request.Credentials = credentialProvider.GetCredentials(request, CredentialType.RequestCredentials, retrying: credentialsRetryCount > 0);

                    continueIfFailed = request.Credentials != null;

                    credentialsRetryCount++;
                }

                try
                {
                    ICredentials credentials = request.Credentials;

                    SetKeepAliveHeaders(request, previousResponse);

                    if (usingSTSAuth)
                    {
                        // Add request headers if the server requires STS based auth.
                        STSAuthHelper.PrepareSTSRequest(request);
                    }

                    // Prepare the request, we do something like write to the request stream
                    // which needs to happen last before the request goes out
                    prepareRequest(request);

                    // Wrap the credentials in a CredentialCache in case there is a redirect
                    // and credentials need to be kept around.
                    request.Credentials = request.Credentials.AsCredentialCache(request.RequestUri);

                    WebResponse response = request.GetResponse();

                    // Cache the proxy and credentials
                    proxyCache.Add(request.Proxy);

                    credentialCache.Add(request.RequestUri, credentials);
                    credentialCache.Add(response.ResponseUri, credentials);

                    return response;
                }
                catch (WebException ex)
                {
                    using (IHttpWebResponse response = GetResponse(ex.Response))
                    {
                        if (response == null &&
                            ex.Status != WebExceptionStatus.SecureChannelFailure)
                        {
                            // No response, something went wrong so just rethrow
                            throw;
                        }

                        // Special case https connections that might require authentication
                        if (ex.Status == WebExceptionStatus.SecureChannelFailure)
                        {
                            if (continueIfFailed)
                            {
                                // Act like we got a 401 so that we prompt for credentials on the next request
                                previousStatusCode = HttpStatusCode.Unauthorized;
                                continue;
                            }
                            throw;
                        }

                        // If we were trying to authenticate the proxy or the request and succeeded, cache the result.
                        if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired &&
                            response.StatusCode != HttpStatusCode.ProxyAuthenticationRequired)
                        {

                            proxyCache.Add(request.Proxy);
                        }
                        else if (previousStatusCode == HttpStatusCode.Unauthorized &&
                                 response.StatusCode != HttpStatusCode.Unauthorized)
                        {
                            credentialCache.Add(request.RequestUri, request.Credentials);
                            credentialCache.Add(response.ResponseUri, request.Credentials);
                        }

                        usingSTSAuth = STSAuthHelper.TryRetrieveSTSToken(request.RequestUri, response);
                        
                        if (!IsAuthenticationResponse(response) || !continueIfFailed)
                        {
                            throw;
                        }

                        previousResponse = response;
                        previousStatusCode = previousResponse.StatusCode;
                    }
                }
            }
        }
Esempio n. 2
0
        internal static WebResponse GetResponse(Func <WebRequest> createRequest,
                                                Action <WebRequest> prepareRequest,
                                                IProxyCache proxyCache,
                                                ICredentialCache credentialCache,
                                                ICredentialProvider credentialProvider)
        {
            HttpWebRequest   previousRequest    = null;
            IHttpWebResponse previousResponse   = null;
            HttpStatusCode?  previousStatusCode = null;
            bool             usingSTSAuth       = false;
            bool             continueIfFailed   = true;
            int proxyCredentialsRetryCount      = 0;
            int credentialsRetryCount           = 0;

            while (true)
            {
                // Create the request
                var request = (HttpWebRequest)createRequest();
                request.Proxy = proxyCache.GetProxy(request.RequestUri);
                if (request.Proxy != null && request.Proxy.Credentials == null)
                {
                    request.Proxy.Credentials = CredentialCache.DefaultCredentials;
                }

                if (previousResponse == null || ShouldKeepAliveBeUsedInRequest(previousRequest, previousResponse))
                {
                    // Try to use the cached credentials (if any, for the first request)
                    request.Credentials = credentialCache.GetCredentials(request.RequestUri);

                    // If there are no cached credentials, use the default ones
                    if (request.Credentials == null)
                    {
                        request.UseDefaultCredentials = true;
                    }
                }
                else if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                {
                    request.Proxy.Credentials = credentialProvider.GetCredentials(request, CredentialType.ProxyCredentials, retrying: proxyCredentialsRetryCount > 0);

                    continueIfFailed = request.Proxy.Credentials != null;

                    proxyCredentialsRetryCount++;
                }
                else if ((previousStatusCode == HttpStatusCode.Unauthorized) && !usingSTSAuth)
                {
                    // If we are using STS, the auth's being performed by a request header. We do not need to ask the user for credentials at this point.
                    request.Credentials = credentialProvider.GetCredentials(request, CredentialType.RequestCredentials, retrying: credentialsRetryCount > 0);

                    continueIfFailed = request.Credentials != null;

                    credentialsRetryCount++;
                }

                try
                {
                    ICredentials credentials = request.Credentials;

                    SetKeepAliveHeaders(request, previousResponse);

                    if (usingSTSAuth)
                    {
                        // Add request headers if the server requires STS based auth.
                        STSAuthHelper.PrepareSTSRequest(request);
                    }

                    // Prepare the request, we do something like write to the request stream
                    // which needs to happen last before the request goes out
                    prepareRequest(request);

                    // Wrap the credentials in a CredentialCache in case there is a redirect
                    // and credentials need to be kept around.
                    request.Credentials = request.Credentials.AsCredentialCache(request.RequestUri);

                    WebResponse response = request.GetResponse();

                    // Cache the proxy and credentials
                    proxyCache.Add(request.Proxy);

                    credentialCache.Add(request.RequestUri, credentials);
                    credentialCache.Add(response.ResponseUri, credentials);

                    return(response);
                }
                catch (WebException ex)
                {
                    using (IHttpWebResponse response = GetResponse(ex.Response))
                    {
                        if (response == null &&
                            ex.Status != WebExceptionStatus.SecureChannelFailure)
                        {
                            // No response, something went wrong so just rethrow
                            throw;
                        }

                        // Special case https connections that might require authentication
                        if (ex.Status == WebExceptionStatus.SecureChannelFailure)
                        {
                            if (continueIfFailed)
                            {
                                // Act like we got a 401 so that we prompt for credentials on the next request
                                previousStatusCode = HttpStatusCode.Unauthorized;
                                continue;
                            }
                            throw;
                        }

                        // If we were trying to authenticate the proxy or the request and succeeded, cache the result.
                        if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired &&
                            response.StatusCode != HttpStatusCode.ProxyAuthenticationRequired)
                        {
                            proxyCache.Add(request.Proxy);
                        }
                        else if (previousStatusCode == HttpStatusCode.Unauthorized &&
                                 response.StatusCode != HttpStatusCode.Unauthorized)
                        {
                            credentialCache.Add(request.RequestUri, request.Credentials);
                            credentialCache.Add(response.ResponseUri, request.Credentials);
                        }

                        usingSTSAuth = STSAuthHelper.TryRetrieveSTSToken(request.RequestUri, response);

                        if (!IsAuthenticationResponse(response) || !continueIfFailed)
                        {
                            throw;
                        }

                        previousRequest    = request;
                        previousResponse   = response;
                        previousStatusCode = previousResponse.StatusCode;
                    }
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Keeps sending requests until a response code that doesn't require authentication happens or if
        /// the request requires authentication and the user has stopped trying to enter them (i.e. they hit cancel when they are prompted).
        /// </summary>
        internal static WebResponse GetResponse(Func<WebRequest> createRequest,
                                                Action<WebRequest> prepareRequest,
                                                IProxyCache proxyCache,
                                                ICredentialCache credentialCache,
                                                ICredentialProvider credentialProvider)
        {
            HttpStatusCode? previousStatusCode = null;
            string authType = null;
            bool continueIfFailed = true;

            while (true)
            {
                // Create the request
                WebRequest request = createRequest();
                request.Proxy = proxyCache.GetProxy(request.RequestUri);
                if (request.Proxy != null && request.Proxy.Credentials == null)
                {
                    request.Proxy.Credentials = CredentialCache.DefaultCredentials;
                }

                if (previousStatusCode == null)
                {
                    // Try to use the cached credentials (if any, for the first request)
                    request.Credentials = credentialCache.GetCredentials(request.RequestUri);

                    if (request.Credentials == null)
                    {
                        // If there are no cached credentials, use the default ones
                        request.UseDefaultCredentials = true;
                    }
                }
                else if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                {
                    request.Proxy.Credentials = credentialProvider.GetCredentials(request, CredentialType.ProxyCredentials);

                    continueIfFailed = request.Proxy.Credentials != null;
                }
                else if (previousStatusCode == HttpStatusCode.Unauthorized)
                {
                    request.Credentials = credentialProvider.GetCredentials(request, CredentialType.RequestCredentials);

                    continueIfFailed = request.Credentials != null;
                }

                try
                {
                    ICredentials credentials = request.Credentials;

                    // KeepAlive is required for NTLM and Kerberos authentication.
                    // REVIEW: The WWW-Authenticate header is tricky to parse so a Equals might not be correct
                    if (!String.Equals(authType, "NTLM", StringComparison.OrdinalIgnoreCase) &&
                        !String.Equals(authType, "Kerberos", StringComparison.OrdinalIgnoreCase))
                    {
                        // This is to work around the "The underlying connection was closed: An unexpected error occurred on a receive."
                        // exception.
                        var httpRequest = (HttpWebRequest)request;
                        httpRequest.KeepAlive = false;
                        httpRequest.ProtocolVersion = HttpVersion.Version10;
                    }

                    // Prepare the request, we do something like write to the request stream
                    // which needs to happen last before the request goes out
                    prepareRequest(request);

                    // Wrap the credentials in a CredentialCache in case there is a redirect
                    // and credentials need to be kept around.
                    request.Credentials = request.Credentials.AsCredentialCache(request.RequestUri);

                    WebResponse response = request.GetResponse();

                    // Cache the proxy and credentials
                    proxyCache.Add(request.Proxy);

                    credentialCache.Add(request.RequestUri, credentials);
                    credentialCache.Add(response.ResponseUri, credentials);

                    return response;
                }
                catch (WebException ex)
                {
                    IHttpWebResponse response = GetResponse(ex.Response);
                    if (response == null &&
                        ex.Status != WebExceptionStatus.SecureChannelFailure)
                    {
                        // No response, something went wrong so just rethrow
                        throw;
                    }

                    // Special case https connections that might require authentication
                    if (ex.Status == WebExceptionStatus.SecureChannelFailure)
                    {
                        if (continueIfFailed)
                        {
                            // Act like we got a 401 so that we prompt for credentials on the next request
                            previousStatusCode = HttpStatusCode.Unauthorized;
                            continue;
                        }
                        throw;
                    }

                    // If we were trying to authenticate the proxy or the request and succeeded, cache the result.
                    if (previousStatusCode == HttpStatusCode.ProxyAuthenticationRequired &&
                        response.StatusCode != HttpStatusCode.ProxyAuthenticationRequired)
                    {

                        proxyCache.Add(request.Proxy);
                    }
                    else if (previousStatusCode == HttpStatusCode.Unauthorized &&
                             response.StatusCode != HttpStatusCode.Unauthorized)
                    {

                        credentialCache.Add(request.RequestUri, request.Credentials);
                        credentialCache.Add(response.ResponseUri, request.Credentials);
                    }

                    if (!IsAuthenticationResponse(response) || !continueIfFailed)
                    {
                        throw;
                    }

                    using (response)
                    {
                        previousStatusCode = response.StatusCode;
                        authType = response.AuthType;
                    }
                }
            }
        }