diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e4b6a..046c782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## 2.3.0 (2021-06-11) + +- Floating latest dependencies for .NET Core 3.1 and .NET 5 +- Fixed [ConfigurePrimaryHttpMessageHandler() not loading handler](https://github.com/dotnet/extensions/issues/851) + ## 2.2.0 (2021-05-26) - Update dependencies [#51](https://github.com/akunzai/GSS.Authorization.OAuth/pull/51) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e160861..6c4f8d8 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -9,7 +9,7 @@ true true enable - 2.2.0 + 2.3.0 diff --git a/src/GSS.Authorization.OAuth.HttpClient/GSS.Authorization.OAuth.HttpClient.csproj b/src/GSS.Authorization.OAuth.HttpClient/GSS.Authorization.OAuth.HttpClient.csproj index 3612a29..9d5fc38 100644 --- a/src/GSS.Authorization.OAuth.HttpClient/GSS.Authorization.OAuth.HttpClient.csproj +++ b/src/GSS.Authorization.OAuth.HttpClient/GSS.Authorization.OAuth.HttpClient.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;netcoreapp3.1;net5.0 OAuth 1.0 authorized HttpClient, friendly with HttpClientFactory OAuth;HttpClient;HttpHandler GSS.Authorization.OAuth @@ -12,8 +12,19 @@ - + + + + + + + + + + + + diff --git a/src/GSS.Authorization.OAuth.HttpClient/OAuthHttpHandler.cs b/src/GSS.Authorization.OAuth.HttpClient/OAuthHttpHandler.cs index d779f7c..7e5b6e5 100644 --- a/src/GSS.Authorization.OAuth.HttpClient/OAuthHttpHandler.cs +++ b/src/GSS.Authorization.OAuth.HttpClient/OAuthHttpHandler.cs @@ -29,7 +29,7 @@ public OAuthHttpHandler(IOptions options, IRequestSigne if (request == null) throw new ArgumentNullException(nameof(request)); var tokenCredentials = await _options.TokenCredentialProvider(request).ConfigureAwait(false); - var queryString = QueryHelpers.ParseQuery(request.RequestUri.Query); + var queryString = QueryHelpers.ParseQuery(request.RequestUri?.Query); if (_options.SignedAsBody && request.Content != null && string.Equals(request.Content.Headers?.ContentType?.MediaType, ApplicationFormUrlEncoded, StringComparison.OrdinalIgnoreCase)) { @@ -43,15 +43,15 @@ public OAuthHttpHandler(IOptions options, IRequestSigne } } - var parameters = _signer.AppendAuthorizationParameters(request.Method, request.RequestUri, _options, + var parameters = _signer.AppendAuthorizationParameters(request.Method, request.RequestUri!, _options, formData, tokenCredentials); - var values = new List>(); + var values = new List>(); foreach (var parameter in parameters) { if (!queryString.ContainsKey(parameter.Key)) { values.AddRange(parameter.Value.Select(value => - new KeyValuePair(parameter.Key, value))); + new KeyValuePair(parameter.Key, value))); } } @@ -60,7 +60,7 @@ public OAuthHttpHandler(IOptions options, IRequestSigne } else if (_options.SignedAsQuery) { - var parameters = _signer.AppendAuthorizationParameters(request.Method, request.RequestUri, _options, + var parameters = _signer.AppendAuthorizationParameters(request.Method, request.RequestUri!, _options, queryString, tokenCredentials); var values = new List(); foreach (var parameter in parameters) @@ -71,13 +71,13 @@ public OAuthHttpHandler(IOptions options, IRequestSigne } } - request.RequestUri = new UriBuilder(request.RequestUri) { Query = "?" + string.Join("&", values) }.Uri; + request.RequestUri = new UriBuilder(request.RequestUri!) { Query = "?" + string.Join("&", values) }.Uri; } else { request.Headers.Authorization = _signer.GetAuthorizationHeader( request.Method, - request.RequestUri, + request.RequestUri!, _options, queryString, tokenCredentials); diff --git a/src/GSS.Authorization.OAuth2.HttpClient/GSS.Authorization.OAuth2.HttpClient.csproj b/src/GSS.Authorization.OAuth2.HttpClient/GSS.Authorization.OAuth2.HttpClient.csproj index 88b2c06..9d95fcb 100644 --- a/src/GSS.Authorization.OAuth2.HttpClient/GSS.Authorization.OAuth2.HttpClient.csproj +++ b/src/GSS.Authorization.OAuth2.HttpClient/GSS.Authorization.OAuth2.HttpClient.csproj @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.0;netcoreapp3.1;net5.0 OAuth 2.0 authorized HttpClient, friendly with HttpClientFactory OAuth;OAuth2;HttpClient;HttpHandler GSS.Authorization.OAuth2 @@ -12,9 +12,22 @@ + + + + - + + + + + + + + + + diff --git a/src/GSS.Authorization.OAuth2.HttpClient/OAuth2HttpHandler.cs b/src/GSS.Authorization.OAuth2.HttpClient/OAuth2HttpHandler.cs index bfdb8d8..b92a573 100644 --- a/src/GSS.Authorization.OAuth2.HttpClient/OAuth2HttpHandler.cs +++ b/src/GSS.Authorization.OAuth2.HttpClient/OAuth2HttpHandler.cs @@ -53,8 +53,6 @@ public OAuth2HttpHandler(IAuthorizer authorizer, IMemoryCache memoryCache) try { var accessToken = await _authorizer.GetAccessTokenAsync(cancellationToken).ConfigureAwait(false); - if (accessToken == null) - return AccessToken.Empty; if (accessToken.ExpiresInSeconds > 0) { _memoryCache.Set(_cacheKey, accessToken, accessToken.ExpiresIn); @@ -73,10 +71,10 @@ public OAuth2HttpHandler(IAuthorizer authorizer, IMemoryCache memoryCache) private static void TrySetAuthorizationHeaderToRequest(AccessToken accessToken, HttpRequestMessage request) { - if (!string.IsNullOrWhiteSpace(accessToken?.Token)) + if (!string.IsNullOrWhiteSpace(accessToken.Token)) { request.Headers.Authorization = - new AuthenticationHeaderValue(AuthorizerDefaults.Bearer, accessToken?.Token); + new AuthenticationHeaderValue(AuthorizerDefaults.Bearer, accessToken.Token); } } } diff --git a/test/GSS.Authorization.OAuth.HttpClient.Tests/GSS.Authorization.OAuth.HttpClient.Tests.csproj b/test/GSS.Authorization.OAuth.HttpClient.Tests/GSS.Authorization.OAuth.HttpClient.Tests.csproj index 9e4146b..7cc4afd 100644 --- a/test/GSS.Authorization.OAuth.HttpClient.Tests/GSS.Authorization.OAuth.HttpClient.Tests.csproj +++ b/test/GSS.Authorization.OAuth.HttpClient.Tests/GSS.Authorization.OAuth.HttpClient.Tests.csproj @@ -20,7 +20,6 @@ - diff --git a/test/GSS.Authorization.OAuth.HttpClient.Tests/OAuthHttpClientTests.cs b/test/GSS.Authorization.OAuth.HttpClient.Tests/OAuthHttpClientTests.cs index 01e4fda..dcc5187 100644 --- a/test/GSS.Authorization.OAuth.HttpClient.Tests/OAuthHttpClientTests.cs +++ b/test/GSS.Authorization.OAuth.HttpClient.Tests/OAuthHttpClientTests.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.Specialized; using System.Globalization; using System.Linq; using System.Net; @@ -43,19 +42,19 @@ public async Task HttpClient_AccessProtectedResourceWithAuthorizationHeader_Shou { // Arrange var services = new ServiceCollection() - .AddOAuthHttpClient((_, options) => + .AddOAuthHttpClient((_, handlerOptions) => { - options.ClientCredentials = new OAuthCredential( + handlerOptions.ClientCredentials = new OAuthCredential( _configuration["OAuth:ClientId"], _configuration["OAuth:ClientSecret"]); - options.TokenCredentials = _tokenCredentials; + handlerOptions.TokenCredentials = _tokenCredentials; if (_mockHttp != null) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() .ToString(CultureInfo.InvariantCulture); var nonce = generateNonce(); - options.TimestampProvider = () => timestamp; - options.NonceProvider = () => nonce; + handlerOptions.TimestampProvider = () => timestamp; + handlerOptions.NonceProvider = () => nonce; } }) .ConfigurePrimaryHttpMessageHandler(_ => (HttpMessageHandler)_mockHttp ?? new HttpClientHandler()) @@ -83,20 +82,20 @@ public async Task HttpClient_AccessProtectedResourceWithQueryString_ShouldAuthor { // Arrange var services = new ServiceCollection() - .AddOAuthHttpClient((_, options) => + .AddOAuthHttpClient((_, handlerOptions) => { - options.ClientCredentials = new OAuthCredential( + handlerOptions.ClientCredentials = new OAuthCredential( _configuration["OAuth:ClientId"], _configuration["OAuth:ClientSecret"]); - options.TokenCredentials = _tokenCredentials; - options.SignedAsQuery = true; + handlerOptions.TokenCredentials = _tokenCredentials; + handlerOptions.SignedAsQuery = true; if (_mockHttp != null) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() .ToString(CultureInfo.InvariantCulture); var nonce = generateNonce(); - options.TimestampProvider = () => timestamp; - options.NonceProvider = () => nonce; + handlerOptions.TimestampProvider = () => timestamp; + handlerOptions.NonceProvider = () => nonce; } }) .ConfigurePrimaryHttpMessageHandler(_ => (HttpMessageHandler)_mockHttp ?? new HttpClientHandler()) @@ -136,20 +135,20 @@ public async Task HttpClient_AccessProtectedResourceWithFormBody_ShouldAuthorize { // Arrange var services = new ServiceCollection() - .AddOAuthHttpClient((_, options) => + .AddOAuthHttpClient((_, handlerOptions) => { - options.ClientCredentials = new OAuthCredential( + handlerOptions.ClientCredentials = new OAuthCredential( _configuration["OAuth:ClientId"], _configuration["OAuth:ClientSecret"]); - options.TokenCredentials = _tokenCredentials; - options.SignedAsBody = true; + handlerOptions.TokenCredentials = _tokenCredentials; + handlerOptions.SignedAsBody = true; if (_mockHttp != null) { var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() .ToString(CultureInfo.InvariantCulture); var nonce = generateNonce(); - options.TimestampProvider = () => timestamp; - options.NonceProvider = () => nonce; + handlerOptions.TimestampProvider = () => timestamp; + handlerOptions.NonceProvider = () => nonce; } }) .ConfigurePrimaryHttpMessageHandler(_ => (HttpMessageHandler)_mockHttp ?? new HttpClientHandler()) diff --git a/test/GSS.Authorization.OAuth.HttpClient.Tests/ServiceCollectionExtensionsTests.cs b/test/GSS.Authorization.OAuth.HttpClient.Tests/ServiceCollectionExtensionsTests.cs index 7273978..78c3744 100644 --- a/test/GSS.Authorization.OAuth.HttpClient.Tests/ServiceCollectionExtensionsTests.cs +++ b/test/GSS.Authorization.OAuth.HttpClient.Tests/ServiceCollectionExtensionsTests.cs @@ -1,7 +1,9 @@ using System; using System.Net.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Http; using Microsoft.Extensions.Options; +using RichardSzalay.MockHttp; using Xunit; namespace GSS.Authorization.OAuth.HttpClient.Tests @@ -134,6 +136,29 @@ public void AddOAuthHttpClient_WithValidConfigureOptions_ShouldAddInServiceProvi // Assert Assert.NotNull(client); } + + [Fact] + public void AddOAuthHttpClient_WithGenericConfigurePrimaryHttpMessageHandler_ShouldAddInHttpMessageHandlerBuilderActions() + { + // Arrange + var mockHttp = new MockHttpMessageHandler(); + var collection = new ServiceCollection(); + var builder = collection + .AddSingleton(mockHttp) + .AddOAuthHttpClient((_, options) => + { + options.ClientCredentials = new OAuthCredential("foo", "bar"); + options.TokenCredentials = new OAuthCredential("foo", "bar"); + }).ConfigurePrimaryHttpMessageHandler(); + var services = builder.Services.BuildServiceProvider(); + + // Act + var optionsMonitor = services.GetRequiredService>(); + + // Assert + var httpClientFactoryOptions = optionsMonitor.Get(builder.Name); + Assert.Contains(httpClientFactoryOptions.HttpMessageHandlerBuilderActions, x => x.Target?.ToString()?.Contains("MockHttpMessageHandler") == true); + } [Fact] public void AddNamedOAuthHttpClient_WithValidConfigureOptions_ShouldAddInHttpClientFactory() @@ -243,7 +268,7 @@ public void AddNamedOAuthHttpClient_WithCustomConfigureOptions_ShouldAddInServic } [Fact] - public void AddTypedOAuthHttpClients_WithDifferenctSigners_ShouldAddInServiceProvider() + public void AddTypedOAuthHttpClients_WithDifferentSigners_ShouldAddInServiceProvider() { // Arrange var collection = new ServiceCollection(); diff --git a/test/GSS.Authorization.OAuth2.HttpClient.Tests/GSS.Authorization.OAuth2.HttpClient.Tests.csproj b/test/GSS.Authorization.OAuth2.HttpClient.Tests/GSS.Authorization.OAuth2.HttpClient.Tests.csproj index 1806d54..07bd1bf 100644 --- a/test/GSS.Authorization.OAuth2.HttpClient.Tests/GSS.Authorization.OAuth2.HttpClient.Tests.csproj +++ b/test/GSS.Authorization.OAuth2.HttpClient.Tests/GSS.Authorization.OAuth2.HttpClient.Tests.csproj @@ -20,7 +20,6 @@ - diff --git a/test/GSS.Authorization.OAuth2.HttpClient.Tests/ServiceCollectionExtensionsTests.cs b/test/GSS.Authorization.OAuth2.HttpClient.Tests/ServiceCollectionExtensionsTests.cs index 854ed01..65883bd 100644 --- a/test/GSS.Authorization.OAuth2.HttpClient.Tests/ServiceCollectionExtensionsTests.cs +++ b/test/GSS.Authorization.OAuth2.HttpClient.Tests/ServiceCollectionExtensionsTests.cs @@ -4,7 +4,9 @@ using System.Net; using System.Net.Http; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Http; using Microsoft.Extensions.Options; +using RichardSzalay.MockHttp; using Xunit; namespace GSS.Authorization.OAuth2.HttpClient.Tests @@ -103,9 +105,33 @@ public void AddOAuth2HttpClient_WithValidConfigureOptions_ShouldNotThrows() // Assert Assert.NotNull(authorizerOptions); } + + [Fact] + public void AddOAuth2HttpClient_WithGenericConfigurePrimaryHttpMessageHandler_ShouldAddInHttpMessageHandlerBuilderActions() + { + // Arrange + var mockHttp = new MockHttpMessageHandler(); + var collection = new ServiceCollection(); + var builder = collection + .AddSingleton(mockHttp) + .AddOAuth2HttpClient((_, options) => + { + options.AccessTokenEndpoint = new Uri("https://example.com"); + options.ClientId = "foo"; + options.ClientSecret = "bar"; + }).ConfigurePrimaryHttpMessageHandler(); + var services = builder.Services.BuildServiceProvider(); + + // Act + var optionsMonitor = services.GetRequiredService>(); + + // Assert + var httpClientFactoryOptions = optionsMonitor.Get(builder.Name); + Assert.Contains(httpClientFactoryOptions.HttpMessageHandlerBuilderActions, x => x.Target?.ToString()?.Contains("MockHttpMessageHandler") == true); + } [Fact] - public void AddOAuth2HttpClient_WithoutCredentials_ShouldThorwsForResourceOwnerCredentialsAuthorizer() + public void AddOAuth2HttpClient_WithoutCredentials_ShouldThrowsForResourceOwnerCredentialsAuthorizer() { // Arrange var collection = new ServiceCollection(); @@ -124,7 +150,7 @@ public void AddOAuth2HttpClient_WithoutCredentials_ShouldThorwsForResourceOwnerC } [Fact] - public void AddOAuth2HttpClient_WithCredentials_ShouldNotThorwsForResourceOwnerCredentialsAuthorizer() + public void AddOAuth2HttpClient_WithCredentials_ShouldNotThrowsForResourceOwnerCredentialsAuthorizer() { // Arrange var collection = new ServiceCollection(); @@ -214,7 +240,7 @@ public void AddTypedOAuth2HttpClient_WithClientCredentialsAuthorizer_ShouldAddIn } [Fact] - public void AddOAuth2HttpClients_WithDifferenctAuthorizers_ShouldAddAuthroizersInServiceProvider() + public void AddOAuth2HttpClients_WithDifferentAuthorizers_ShouldAddAuthorizersInServiceProvider() { // Arrange var collection = new ServiceCollection();