/// <summary> /// Attempts to post-authenticate a request given an unauthorized response using /// the Bearer challenge cache and the application supplied AuthenticationCallback. /// </summary> /// <param name="url">The unauthorized response</param> /// <returns>The access token to use for the request</returns> protected string PostAuthenticate(HttpResponseMessage response) { // An HTTP 401 Not Authorized error; handle if an authentication callback has been supplied if (OnAuthenticate != null) { // Extract the WWW-Authenticate header and determine if it represents an OAuth2 Bearer challenge var authenticateHeader = response.Headers.WwwAuthenticate.ElementAt(0).ToString(); if (HttpBearerChallenge.IsBearerChallenge(authenticateHeader)) { var challenge = new HttpBearerChallenge(response.RequestMessage.RequestUri, authenticateHeader); if (challenge != null) { // Update challenge cache HttpBearerChallengeCache.GetInstance().SetChallengeForURL(response.RequestMessage.RequestUri, challenge); // We have an authentication challenge, use it to get a new authorization token return(OnAuthenticate(challenge.AuthorizationServer, challenge.Resource, challenge.Scope)); } } } return(null); }
/// <summary> /// Updates the <see cref="HttpBearerChallengeCache"/> when the specified response has a return code of 401 /// </summary> /// <param name="response">The response to evaluate</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns></returns> protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken) { // if the response came back as 401 and the response contains a bearer challenge update the challenge cache if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { HttpBearerChallenge challenge = HttpBearerChallenge.GetBearerChallengeFromResponse(response); if (challenge != null) { // Update challenge cache HttpBearerChallengeCache.GetInstance().SetChallengeForURL(response.RequestMessage.RequestUri, challenge); } } return(response); }
private async Task <OAuthToken> GetOAuthTokenAsync(HttpResponseMessage response, HttpRequestMessage unauthorizedRequest, CancellationToken cancellationToken = default) { AuthenticationHeaderValue?bearerHeader = response.Headers.WwwAuthenticate .AsEnumerable() .FirstOrDefault(header => header.Scheme == HttpBearerChallenge.Bearer); if (bearerHeader is null) { throw new AuthenticationException($"Bearer header not contained in unauthorized response from {response.RequestMessage?.RequestUri}"); } HttpBearerChallenge challenge = HttpBearerChallenge.Parse(bearerHeader.Parameter); Uri authenticateUri = new($"{challenge.Realm}?service={challenge.Service}&scope={challenge.Scope}"); HttpRequestMessage authenticateRequest = new(HttpMethod.Get, authenticateUri); authenticateRequest.Headers.Authorization = unauthorizedRequest.Headers.Authorization; cancellationToken.ThrowIfCancellationRequested(); response = await base.SendAsync(authenticateRequest, cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode(); cancellationToken.ThrowIfCancellationRequested(); #if NET5_0_OR_GREATER string tokenContent = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false); #else string tokenContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); #endif try { return(SafeJsonConvert.DeserializeObject <OAuthToken>(tokenContent)); } catch (JsonException e) { throw new SerializationException("Unable to deserialize the response.", tokenContent, e); } }