async Task <ICredentials> PromptForCredentialsAsync( CredentialType type, AmbientAuthenticationState authState, CancellationToken token) { ICredentials promptCredentials; try { // Only one prompt may display at a time. await credentialPromptLock.WaitAsync(); // Get the proxy for this URI so we can pass it to the credentialService methods // this lets them use the proxy if they have to hit the network. var proxyCache = WebRequestHelper.ProxyCache; var proxy = proxyCache?.GetProxy(source); bool isRetry = authState.AuthenticationRetriesCount > 0; promptCredentials = await credentialService.GetCredentialsAsync(source, proxy, type, isRetry, token); if (promptCredentials == null) { // If this is the case, this means none of the credential providers were able to // handle the credential request or no credentials were available for the // endpoint. authState.Block(); } else { authState.Increment(); } } catch (OperationCanceledException) { // This indicates a non-human cancellation. throw; } catch (Exception) { // If this is the case, this means there was a fatal exception when interacting // with the credential service (or its underlying credential providers). Either way, // block asking for credentials for the live of this operation. promptCredentials = null; authState.Block(); } finally { credentialPromptLock.Release(); } return(promptCredentials); }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpResponseMessage response = null; ICredentials promptCredentials = null; var authState = new AmbientAuthenticationState(); // 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 beforeLockVersion = credentials.Version; response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false); if (credentialService == null) { return(response); } if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) { promptCredentials = await AcquireCredentialsAsync( authState, beforeLockVersion, cancellationToken); if (promptCredentials == null) { return(response); } continue; } return(response); } }
async Task <ICredentials> AcquireCredentialsAsync(AmbientAuthenticationState authState, Guid credentialsVersion, CancellationToken cancellationToken) { try { // Only one request may prompt and attempt to auth at a time await httpClientLock.WaitAsync(); cancellationToken.ThrowIfCancellationRequested(); // Auth may have happened on another thread, if so just continue if (credentialsVersion != credentials.Version) { return(credentials.Credentials); } if (authState.IsBlocked) { cancellationToken.ThrowIfCancellationRequested(); return(null); } var promptCredentials = await PromptForCredentialsAsync( CredentialType.RequestCredentials, authState, cancellationToken); if (promptCredentials == null) { return(null); } credentials.Credentials = promptCredentials; return(promptCredentials); } finally { httpClientLock.Release(); } }