예제 #1
0
        private async Task <HttpResponseMessage> SendWithCredentialSupportAsync(
            Func <HttpRequestMessage> requestFactory,
            HttpCompletionOption completionOption,
            ILogger log,
            CancellationToken cancellationToken)
        {
            HttpResponseMessage response          = null;
            ICredentials        promptCredentials = null;

            // Create the http client on the first call
            if (_httpClient == null)
            {
                await _httpClientLock.WaitAsync();

                try
                {
                    // Double check
                    if (_httpClient == null)
                    {
                        await UpdateHttpClient();
                    }
                }
                finally
                {
                    _httpClientLock.Release();
                }
            }

            // Update the request for STS
            Func <HttpRequestMessage> requestWithStsFactory = () =>
            {
                var request = requestFactory();
                STSAuthHelper.PrepareSTSRequest(_baseUri, CredentialStore.Instance, request);
                return(request);
            };

            // Authorizing may take multiple attempts
            while (true)
            {
                // Clean up any previous responses
                if (response != null)
                {
                    response.Dispose();
                }

                // store the auth state before sending the request
                var beforeLockId = _lastAuthId;

                // Read the response headers before reading the entire stream to avoid timeouts from large packages.
                response = await _retryHandler.SendAsync(
                    _httpClient,
                    requestWithStsFactory,
                    completionOption,
                    log,
                    cancellationToken);

                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    try
                    {
                        // Only one request may prompt and attempt to auth at a time
                        await _httpClientLock.WaitAsync();

                        // Auth may have happened on another thread, if so just continue
                        if (beforeLockId != _lastAuthId)
                        {
                            continue;
                        }

                        // Give up after 3 tries.
                        _authRetries++;
                        if (_authRetries > 3)
                        {
                            return(response);
                        }

                        // Windows auth
                        if (STSAuthHelper.TryRetrieveSTSToken(_baseUri, CredentialStore.Instance, response))
                        {
                            // Auth token found, create a new message handler and retry.
                            await UpdateHttpClient();

                            continue;
                        }

                        // Prompt the user
                        promptCredentials = await PromptForCredentials(cancellationToken);

                        if (promptCredentials != null)
                        {
                            // The user entered credentials, create a new message handler that includes
                            // these and retry.
                            await UpdateHttpClient(promptCredentials);

                            continue;
                        }
                    }
                    finally
                    {
                        _httpClientLock.Release();
                    }
                }

                if (promptCredentials != null && HttpHandlerResourceV3.CredentialsSuccessfullyUsed != null)
                {
                    HttpHandlerResourceV3.CredentialsSuccessfullyUsed(_baseUri, promptCredentials);
                }

                return(response);
            }
        }
예제 #2
0
        private async Task <HttpResponseMessage> SendWithCredentialSupportAsync(
            Func <HttpRequestMessage> requestFactory,
            ILogger log,
            CancellationToken cancellationToken)
        {
            HttpResponseMessage response          = null;
            ICredentials        promptCredentials = null;

            // Create the http client on the first call
            if (_httpClient == null)
            {
                await _httpClientLock.WaitAsync();

                try
                {
                    // Double check
                    if (_httpClient == null)
                    {
                        await UpdateHttpClientAsync();
                    }
                }
                finally
                {
                    _httpClientLock.Release();
                }
            }

            // Update the request for STS
            Func <HttpRequestMessage> requestWithStsFactory = () =>
            {
                var request = requestFactory();
                STSAuthHelper.PrepareSTSRequest(_baseUri, CredentialStore.Instance, request);
                return(request);
            };

            // Authorizing may take multiple attempts
            while (true)
            {
                // Clean up any previous responses
                if (response != null)
                {
                    response.Dispose();
                }

                // store the auth state before sending the request
                var beforeLockId = _lastAuthId;

                // Read the response headers before reading the entire stream to avoid timeouts from large packages.
                response = await RetryHandler.SendAsync(
                    _httpClient,
                    requestWithStsFactory,
                    HttpCompletionOption.ResponseHeadersRead,
                    log,
                    cancellationToken);

                if (response.StatusCode == HttpStatusCode.Unauthorized ||
                    response.StatusCode == HttpStatusCode.Forbidden)
                {
                    try
                    {
                        // Only one request may prompt and attempt to auth at a time
                        await _httpClientLock.WaitAsync();

                        // Auth may have happened on another thread, if so just continue
                        if (beforeLockId != _lastAuthId)
                        {
                            continue;
                        }

                        var authState = GetAuthenticationState();

                        authState.Increment();

                        if (authState.IsBlocked)
                        {
                            return(response);
                        }

                        // Windows auth
                        if (response.StatusCode == HttpStatusCode.Unauthorized &&
                            STSAuthHelper.TryRetrieveSTSToken(_baseUri, CredentialStore.Instance, response))
                        {
                            // Auth token found, create a new message handler and retry.
                            await UpdateHttpClientAsync();

                            continue;
                        }

                        // Prompt the user
                        CredentialRequestType type;
                        string message;
                        if (response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            type    = CredentialRequestType.Unauthorized;
                            message = string.Format(
                                CultureInfo.CurrentCulture,
                                Strings.Http_CredentialsForUnauthorized,
                                _packageSource.Source);
                        }
                        else
                        {
                            type    = CredentialRequestType.Forbidden;
                            message = string.Format(
                                CultureInfo.CurrentCulture,
                                Strings.Http_CredentialsForForbidden,
                                _packageSource.Source);
                        }

                        promptCredentials = await PromptForCredentialsAsync(
                            type,
                            message,
                            cancellationToken);

                        if (promptCredentials != null)
                        {
                            // The user entered credentials, create a new message handler that includes
                            // these and retry.
                            await UpdateHttpClientAsync(promptCredentials);

                            continue;
                        }

                        // null means cancelled by user
                        // block subsequent attempts to annoy user with prompts
                        authState.IsBlocked = true;
                        return(response);
                    }
                    finally
                    {
                        _httpClientLock.Release();
                    }
                }

                if (promptCredentials != null && HttpHandlerResourceV3.CredentialsSuccessfullyUsed != null)
                {
                    HttpHandlerResourceV3.CredentialsSuccessfullyUsed(_baseUri, promptCredentials);
                }

                return(response);
            }
        }