private static async ValueTask <bool> TrySetDigestAuthToken(HttpRequestMessage request, NetworkCredential credential, DigestResponse digestResponse, bool isProxyAuth) { string?parameter = await GetDigestTokenForCredential(credential, request, digestResponse).ConfigureAwait(false); // Any errors in obtaining parameter return false and we don't proceed with auth if (string.IsNullOrEmpty(parameter)) { if (NetEventSource.IsEnabled) { NetEventSource.AuthenticationError(request.RequestUri, $"Unable to find 'Digest' authentication token when authenticating with {(isProxyAuth ? "proxy" : "server")}"); } return(false); } var headerValue = new AuthenticationHeaderValue(DigestScheme, parameter); SetRequestAuthenticationHeaderValue(request, headerValue, isProxyAuth); return(true); }
private static async ValueTask <HttpResponseMessage> SendWithAuthAsync(HttpRequestMessage request, Uri authUri, bool async, ICredentials credentials, bool preAuthenticate, bool isProxyAuth, bool doRequestAuth, HttpConnectionPool pool, CancellationToken cancellationToken) { // If preauth is enabled and this isn't proxy auth, try to get a basic credential from the // preauth credentials cache, and if successful, set an auth header for it onto the request. // Currently we only support preauth for Basic. bool performedBasicPreauth = false; if (preAuthenticate) { Debug.Assert(pool.PreAuthCredentials != null); NetworkCredential?credential; lock (pool.PreAuthCredentials) { // Just look for basic credentials. If in the future we support preauth // for other schemes, this will need to search in order of precedence. Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NegotiateScheme) == null); Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, NtlmScheme) == null); Debug.Assert(pool.PreAuthCredentials.GetCredential(authUri, DigestScheme) == null); credential = pool.PreAuthCredentials.GetCredential(authUri, BasicScheme); } if (credential != null) { SetBasicAuthToken(request, credential, isProxyAuth); performedBasicPreauth = true; } } HttpResponseMessage response = await InnerSendAsync(request, async, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false); if (TryGetAuthenticationChallenge(response, isProxyAuth, authUri, credentials, out AuthenticationChallenge challenge)) { switch (challenge.AuthenticationType) { case AuthenticationType.Digest: var digestResponse = new DigestResponse(challenge.ChallengeData); if (await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isProxyAuth).ConfigureAwait(false)) { response.Dispose(); response = await InnerSendAsync(request, async, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false); // Retry in case of nonce timeout in server. if (TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out string?challengeData)) { digestResponse = new DigestResponse(challengeData); if (IsServerNonceStale(digestResponse) && await TrySetDigestAuthToken(request, challenge.Credential, digestResponse, isProxyAuth).ConfigureAwait(false)) { response.Dispose(); response = await InnerSendAsync(request, async, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false); } } } break; case AuthenticationType.Basic: if (performedBasicPreauth) { if (NetEventSource.IsEnabled) { NetEventSource.AuthenticationError(authUri, $"Pre-authentication with {(isProxyAuth ? "proxy" : "server")} failed."); } break; } response.Dispose(); SetBasicAuthToken(request, challenge.Credential, isProxyAuth); response = await InnerSendAsync(request, async, isProxyAuth, doRequestAuth, pool, cancellationToken).ConfigureAwait(false); if (preAuthenticate) { switch (response.StatusCode) { case HttpStatusCode.ProxyAuthenticationRequired: case HttpStatusCode.Unauthorized: if (NetEventSource.IsEnabled) { NetEventSource.AuthenticationError(authUri, $"Pre-authentication with {(isProxyAuth ? "proxy" : "server")} failed."); } break; default: lock (pool.PreAuthCredentials !) { try { if (NetEventSource.IsEnabled) { NetEventSource.Info(pool.PreAuthCredentials, $"Adding Basic credential to cache, uri={authUri}, username={challenge.Credential.UserName}"); } pool.PreAuthCredentials.Add(authUri, BasicScheme, challenge.Credential); } catch (ArgumentException) { // The credential already existed. if (NetEventSource.IsEnabled) { NetEventSource.Info(pool.PreAuthCredentials, $"Basic credential present in cache, uri={authUri}, username={challenge.Credential.UserName}"); } } } break; } } break; } } if (NetEventSource.IsEnabled && response.StatusCode == HttpStatusCode.Unauthorized) { NetEventSource.AuthenticationError(authUri, $"{(isProxyAuth ? "Proxy" : "Server")} authentication failed."); } return(response); }