diff --git a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs index de278483d..d502b47d3 100644 --- a/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs +++ b/src/Microsoft.Identity.Web/DownstreamWebApiSupport/MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions.cs @@ -14,13 +14,29 @@ namespace Microsoft.Identity.Web /// public static class MicrosoftIdentityAuthenticationMessageHandlerHttpClientBuilderExtensions { + private const string ObseleteMessage = "This method which accepts a service name is deprecated. Use the overload that uses the HttpClient name as the service name instead."; + /// /// Adds a named Microsoft Identity user authentication message handler related to a specific configuration section. /// /// Builder. - /// Name of the configuration for the service. /// Configuration. /// The builder for chaining. + public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( + this IHttpClientBuilder builder, + IConfiguration configuration) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddMicrosoftIdentityUserAuthenticationHandler(builder.Name, configuration); + } + + /// + /// Name of the configuration for the service. + [Obsolete(ObseleteMessage)] public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( this IHttpClientBuilder builder, string serviceName, @@ -41,9 +57,23 @@ public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( /// Adds a named Microsoft Identity user authentication message handler initialized with delegates. /// /// Builder. - /// Name of the configuration for the service. /// Action to configure the options. /// The builder for chaining. + public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( + this IHttpClientBuilder builder, + Action configureOptions) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddMicrosoftIdentityUserAuthenticationHandler(builder.Name, configureOptions); + } + + /// + /// Name of the configuration for the service. + [Obsolete(ObseleteMessage)] public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( this IHttpClientBuilder builder, string serviceName, @@ -64,9 +94,23 @@ public static IHttpClientBuilder AddMicrosoftIdentityUserAuthenticationHandler( /// Adds a named Microsoft Identity application authentication message handler related to a specific configuration section. /// /// Builder. - /// Name of the configuration for the service. /// Configuration. /// The builder for chaining. + public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( + this IHttpClientBuilder builder, + IConfiguration configuration) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddMicrosoftIdentityAppAuthenticationHandler(builder.Name, configuration); + } + + /// + /// Name of the configuration for the service. + [Obsolete(ObseleteMessage)] public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( this IHttpClientBuilder builder, string serviceName, @@ -87,9 +131,23 @@ public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( /// Adds a named Microsoft Identity application authentication message handler initialized with delegates. /// /// Builder. - /// Name of the configuration for the service. /// Action to configure the options. /// The builder for chaining. + public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( + this IHttpClientBuilder builder, + Action configureOptions) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddMicrosoftIdentityAppAuthenticationHandler(builder.Name, configureOptions); + } + + /// + /// Name of the configuration for the service. + [Obsolete(ObseleteMessage)] public static IHttpClientBuilder AddMicrosoftIdentityAppAuthenticationHandler( this IHttpClientBuilder builder, string serviceName, diff --git a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml index 26f9eb734..0ae94afb2 100644 --- a/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml +++ b/src/Microsoft.Identity.Web/Microsoft.Identity.Web.xml @@ -1023,42 +1023,54 @@ Extension for IHttpClientBuilder for startup initialization of Microsoft Identity authentication handlers. - + Adds a named Microsoft Identity user authentication message handler related to a specific configuration section. Builder. - Name of the configuration for the service. Configuration. The builder for chaining. - + + + Name of the configuration for the service. + + Adds a named Microsoft Identity user authentication message handler initialized with delegates. Builder. - Name of the configuration for the service. Action to configure the options. The builder for chaining. - + + + Name of the configuration for the service. + + Adds a named Microsoft Identity application authentication message handler related to a specific configuration section. Builder. - Name of the configuration for the service. Configuration. The builder for chaining. - + + + Name of the configuration for the service. + + Adds a named Microsoft Identity application authentication message handler initialized with delegates. Builder. - Name of the configuration for the service. Action to configure the options. The builder for chaining. + + + Name of the configuration for the service. + Adds the common configuration for message handlers. diff --git a/tests/Microsoft.Identity.Web.Test/HttpClientBuilderExtensionsTests.cs b/tests/Microsoft.Identity.Web.Test/HttpClientBuilderExtensionsTests.cs index 420dc60df..4522f28eb 100644 --- a/tests/Microsoft.Identity.Web.Test/HttpClientBuilderExtensionsTests.cs +++ b/tests/Microsoft.Identity.Web.Test/HttpClientBuilderExtensionsTests.cs @@ -16,17 +16,18 @@ namespace Microsoft.Identity.Web.Test public class HttpClientBuilderExtensionsTests { private const string HttpClientName = "test-client"; - private const string ServiceName = "test-service"; private readonly IConfigurationSection _configSection; public HttpClientBuilderExtensionsTests() { - _configSection = GetConfigSection(ServiceName); + _configSection = GetConfigSection(); } - private IConfigurationSection GetConfigSection(string key) + private IConfigurationSection GetConfigSection() { + var key = "test-service"; + var builder = new ConfigurationBuilder(); builder.AddInMemoryCollection( new Dictionary() @@ -62,6 +63,13 @@ public DelegatingHandler CreateUserHandler(string serviceName) } } + protected internal class TypedClient + { + public TypedClient(HttpClient client) + { + } + } + [Theory] [InlineData(false)] [InlineData(true)] @@ -74,12 +82,12 @@ public void AddMicrosoftIdentityAuthenticationHandler_WithConfiguration(bool use if (useApp) { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityAppAuthenticationHandler(ServiceName, _configSection); + .AddMicrosoftIdentityAppAuthenticationHandler(_configSection); } else { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityUserAuthenticationHandler(ServiceName, _configSection); + .AddMicrosoftIdentityUserAuthenticationHandler(_configSection); } // assert @@ -88,11 +96,11 @@ public void AddMicrosoftIdentityAuthenticationHandler_WithConfiguration(bool use var provider = services.BuildServiceProvider(); var options = provider.GetRequiredService>(); - Assert.Equal(TestConstants.Scopes, options.Get(ServiceName).Scopes); - Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(ServiceName).Tenant); - Assert.Equal(TestConstants.B2CSignUpSignInUserFlow, options.Get(ServiceName).UserFlow); - Assert.False(options.Get(ServiceName).IsProofOfPossessionRequest); - Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(ServiceName).AuthenticationScheme); + Assert.Equal(TestConstants.Scopes, options.Get(HttpClientName).Scopes); + Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(HttpClientName).Tenant); + Assert.Equal(TestConstants.B2CSignUpSignInUserFlow, options.Get(HttpClientName).UserFlow); + Assert.False(options.Get(HttpClientName).IsProofOfPossessionRequest); + Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(HttpClientName).AuthenticationScheme); } [Theory] @@ -115,12 +123,54 @@ public void AddMicrosoftIdentityAuthenticationHandler_WithOptions(bool useApp) if (useApp) { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityAppAuthenticationHandler(ServiceName, configureOptions); + .AddMicrosoftIdentityAppAuthenticationHandler(configureOptions); } else { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityUserAuthenticationHandler(ServiceName, configureOptions); + .AddMicrosoftIdentityUserAuthenticationHandler(configureOptions); + } + + // assert + Assert.Contains(services, s => s.ServiceType == typeof(IConfigureOptions)); + + var provider = services.BuildServiceProvider(); + var options = provider.GetRequiredService>(); + + Assert.Equal(TestConstants.GraphScopes, options.Get(HttpClientName).Scopes); + Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(HttpClientName).Tenant); + Assert.Equal(TestConstants.B2CResetPasswordUserFlow, options.Get(HttpClientName).UserFlow); + Assert.True(options.Get(HttpClientName).IsProofOfPossessionRequest); + Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(HttpClientName).AuthenticationScheme); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void AddMicrosoftIdentityAuthenticationHandler_WithTypedHttpClient(bool useApp) + { + // arrange + var clientName = typeof(TypedClient).Name; + var services = new ServiceCollection(); + Action configureOptions = options => + { + options.Scopes = TestConstants.GraphScopes; + options.Tenant = TestConstants.TenantIdAsGuid; + options.UserFlow = TestConstants.B2CResetPasswordUserFlow; + options.IsProofOfPossessionRequest = true; + options.AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme; + }; + + // act + if (useApp) + { + services.AddHttpClient() + .AddMicrosoftIdentityAppAuthenticationHandler(configureOptions); + } + else + { + services.AddHttpClient() + .AddMicrosoftIdentityUserAuthenticationHandler(configureOptions); } // assert @@ -129,11 +179,11 @@ public void AddMicrosoftIdentityAuthenticationHandler_WithOptions(bool useApp) var provider = services.BuildServiceProvider(); var options = provider.GetRequiredService>(); - Assert.Equal(TestConstants.GraphScopes, options.Get(ServiceName).Scopes); - Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(ServiceName).Tenant); - Assert.Equal(TestConstants.B2CResetPasswordUserFlow, options.Get(ServiceName).UserFlow); - Assert.True(options.Get(ServiceName).IsProofOfPossessionRequest); - Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(ServiceName).AuthenticationScheme); + Assert.Equal(TestConstants.GraphScopes, options.Get(clientName).Scopes); + Assert.Equal(TestConstants.TenantIdAsGuid, options.Get(clientName).Tenant); + Assert.Equal(TestConstants.B2CResetPasswordUserFlow, options.Get(clientName).UserFlow); + Assert.True(options.Get(clientName).IsProofOfPossessionRequest); + Assert.Equal(JwtBearerDefaults.AuthenticationScheme, options.Get(clientName).AuthenticationScheme); } [Theory] @@ -158,12 +208,12 @@ public void AddMicrosoftIdentityAuthenticationHandler_WithCustomFactory(bool use if (useApp) { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityAppAuthenticationHandler(ServiceName, configureOptions); + .AddMicrosoftIdentityAppAuthenticationHandler(configureOptions); } else { services.AddHttpClient(HttpClientName) - .AddMicrosoftIdentityUserAuthenticationHandler(ServiceName, configureOptions); + .AddMicrosoftIdentityUserAuthenticationHandler(configureOptions); } // assert