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); } }
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); } }