/// <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);
        }
Example #2
0
        /// <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);
        }
    }