From 14b5a413faa39c85a401e7b48cfa19f4d8d26609 Mon Sep 17 00:00:00 2001 From: Jean-Marc Prieur Date: Tue, 31 Mar 2020 10:19:43 -0700 Subject: [PATCH] Proposal for the parameters of AddProtectedApi ... methods (#69) * Proposal for the parameters of AddProtected ... I propose to get rid of hybrid methods, that is provide only: - configuration and section name - or delegates to set the option (several delegates) * Updating the tests to use the new overrides. * Improving the API (removing hybrid solutions between config section and delegates) Addressing pmartak's PR comments. --- .../WebApiServiceCollectionExtensions.cs | 138 +++++------------- .../TodoListService/Startup.cs | 14 +- .../TodoListService/Startup.cs | 2 +- 3 files changed, 49 insertions(+), 105 deletions(-) diff --git a/src/Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs b/src/Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs index 079858786..1e6dff56e 100644 --- a/src/Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs +++ b/src/Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Identity.Client; @@ -23,110 +22,31 @@ namespace Microsoft.Identity.Web /// public static class WebApiServiceCollectionExtensions { - #region Compatibility - /// - /// Protects the Web API with Microsoft identity platform (formerly Azure AD v2.0) - /// This supposes that the configuration files have a section named configSectionName (typically "AzureAD") - /// - /// Service collection to which to add authentication - /// Configuration - /// - public static IServiceCollection AddProtectedApiCallsWebApis( - this IServiceCollection services, - IConfiguration configuration, - string configSectionName = "AzureAd") - { - return AddProtectedWebApiCallsProtectedWebApi(services, - configuration, - configSectionName); - } - #endregion - - /// - /// Protects the Web API with Microsoft identity platform (formerly Azure AD v2.0) - /// This method expects the configuration file will have a section named "AzureAd" with the necessary settings to initialize authentication options. - /// - /// Service collection to which to add this authentication scheme - /// The Configuration object - /// - /// Set to true if you want to debug, or just understand the JwtBearer events. - /// - /// - public static IServiceCollection AddProtectedWebApi( - this IServiceCollection services, - IConfiguration configuration, - X509Certificate2 tokenDecryptionCertificate = null, - string configSectionName = "AzureAd", - bool subscribeToJwtBearerMiddlewareDiagnosticsEvents = false) - { - services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddProtectedWebApi( - configSectionName, - configuration, - options => configuration.Bind(configSectionName, options), - tokenDecryptionCertificate, - subscribeToJwtBearerMiddlewareDiagnosticsEvents); - - return services; - } - /// /// Protects the Web API with Microsoft identity platform (formerly Azure AD v2.0) /// This method expects the configuration file will have a section, named "AzureAd" as default, with the necessary settings to initialize authentication options. /// /// AuthenticationBuilder to which to add this configuration /// The Configuration object - /// An action to configure JwtBearerOptions - /// Token decryption certificate - /// - /// Set to true if you want to debug, or just understand the JwtBearer events. - /// - /// - public static AuthenticationBuilder AddProtectedWebApi( - this AuthenticationBuilder builder, - IConfiguration configuration, - Action configureOptions, - X509Certificate2 tokenDecryptionCertificate = null, - bool subscribeToJwtBearerMiddlewareDiagnosticsEvents = false) - { - return AddProtectedWebApi( - builder, - "AzureAd", - configuration, - JwtBearerDefaults.AuthenticationScheme, - configureOptions, - tokenDecryptionCertificate, - subscribeToJwtBearerMiddlewareDiagnosticsEvents); - } - - /// - /// Protects the Web API with Microsoft identity platform (formerly Azure AD v2.0) - /// This method expects the configuration file will have a section, named "AzureAd" as default, with the necessary settings to initialize authentication options. - /// - /// AuthenticationBuilder to which to add this configuration /// The configuration section with the necessary settings to initialize authentication options - /// The Configuration object - /// An action to configure JwtBearerOptions - /// Token decryption certificate + /// The JwtBearer scheme name to be used. By default it uses "Bearer" + /// Token decryption certificate (null by default) /// /// Set to true if you want to debug, or just understand the JwtBearer events. /// /// public static AuthenticationBuilder AddProtectedWebApi( this AuthenticationBuilder builder, - string configSectionName, IConfiguration configuration, - Action configureOptions, + string configSectionName = "AzureAd", + string jwtBearerScheme = JwtBearerDefaults.AuthenticationScheme, X509Certificate2 tokenDecryptionCertificate = null, bool subscribeToJwtBearerMiddlewareDiagnosticsEvents = false) { - return AddProtectedWebApi( - builder, - configSectionName, - configuration, - JwtBearerDefaults.AuthenticationScheme, - configureOptions, + return builder.AddProtectedWebApi(options => configuration.Bind(configSectionName, options), + options => configuration.Bind(configSectionName, options), tokenDecryptionCertificate, + jwtBearerScheme, subscribeToJwtBearerMiddlewareDiagnosticsEvents); } @@ -138,23 +58,22 @@ public static AuthenticationBuilder AddProtectedWebApi( /// The configuration section with the necessary settings to initialize authentication options /// The Configuration object /// The JwtBearer scheme name to be used. By default it uses "Bearer" - /// An action to configure JwtBearerOptions + /// An action to configure JwtBearerOptions /// Token decryption certificate /// /// Set to true if you want to debug, or just understand the JwtBearer events. /// /// public static AuthenticationBuilder AddProtectedWebApi( - this AuthenticationBuilder builder, - string configSectionName, - IConfiguration configuration, - string jwtBearerScheme, - Action configureOptions, + this AuthenticationBuilder builder, + Action configureJwtBearerOptions, + Action configureMicrosoftIdentityOptions, X509Certificate2 tokenDecryptionCertificate = null, + string jwtBearerScheme = JwtBearerDefaults.AuthenticationScheme, bool subscribeToJwtBearerMiddlewareDiagnosticsEvents = false) { - builder.Services.Configure(jwtBearerScheme, configureOptions); - builder.Services.Configure(options => configuration.Bind(configSectionName, options)); + builder.Services.Configure(jwtBearerScheme, configureJwtBearerOptions); + builder.Services.Configure(configureMicrosoftIdentityOptions); builder.Services.AddHttpContextAccessor(); builder.Services.AddSingleton(); @@ -162,7 +81,10 @@ public static AuthenticationBuilder AddProtectedWebApi( // Change the authentication configuration to accommodate the Microsoft identity platform endpoint (v2.0). builder.AddJwtBearer(jwtBearerScheme, options => { - var microsoftIdentityOptions = configuration.GetSection(configSectionName).Get(); + // TODO: + // Suspect. Why not get the IOption? + var microsoftIdentityOptions = new MicrosoftIdentityOptions();// configuration.GetSection(configSectionName).Get(); + configureMicrosoftIdentityOptions(microsoftIdentityOptions); if (string.IsNullOrWhiteSpace(options.Authority)) options.Authority = AuthorityHelpers.BuildAuthority(microsoftIdentityOptions); @@ -225,17 +147,37 @@ public static AuthenticationBuilder AddProtectedWebApi( /// /// Service collection to which to add authentication /// Configuration + /// Section name in the config file (by default "AzureAD") + /// Scheme for the JwtBearer token /// public static IServiceCollection AddProtectedWebApiCallsProtectedWebApi( this IServiceCollection services, IConfiguration configuration, string configSectionName = "AzureAd", string jwtBearerScheme = JwtBearerDefaults.AuthenticationScheme) + { + return services.AddProtectedWebApiCallsProtectedWebApi( + options => configuration.Bind(configSectionName, options), + options => configuration.Bind(configSectionName, options), + jwtBearerScheme); + } + /// + /// Protects the Web API with Microsoft identity platform (formerly Azure AD v2.0) + /// This supposes that the configuration files have a section named configSectionName (typically "AzureAD") + /// + /// Service collection to which to add authentication + /// Configuration + /// + public static IServiceCollection AddProtectedWebApiCallsProtectedWebApi( + this IServiceCollection services, + Action configureConfidentialClientApplicationOptions, + Action configureMicrosoftIdentityOptions, + string jwtBearerScheme = JwtBearerDefaults.AuthenticationScheme) { services.AddTokenAcquisition(); services.AddHttpContextAccessor(); - services.Configure(options => configuration.Bind(configSectionName, options)); - services.Configure(options => configuration.Bind(configSectionName, options)); + services.Configure(configureConfidentialClientApplicationOptions); + services.Configure(configureMicrosoftIdentityOptions); services.Configure(jwtBearerScheme, options => { diff --git a/tests/B2CWebAppCallsWebApi/TodoListService/Startup.cs b/tests/B2CWebAppCallsWebApi/TodoListService/Startup.cs index bee405b3e..e56756c86 100644 --- a/tests/B2CWebAppCallsWebApi/TodoListService/Startup.cs +++ b/tests/B2CWebAppCallsWebApi/TodoListService/Startup.cs @@ -26,6 +26,8 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { + const string sectionName = "AzureAdB2C"; + // This is required to be instantiated before the OpenIdConnectOptions starts getting configured. // By default, the claims mapping will map claim names in the old format to accommodate older SAML applications. // 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles' @@ -34,12 +36,12 @@ public void ConfigureServices(IServiceCollection services) // Adds Microsoft Identity platform (AAD v2.0) support to protect this Api services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddProtectedWebApi("AzureAdB2C", Configuration, options => - { - Configuration.Bind("AzureAdB2C", options); - - options.TokenValidationParameters.NameClaimType = "name"; - }); + .AddProtectedWebApi(options => + { + Configuration.Bind(sectionName, options); + options.TokenValidationParameters.NameClaimType = "name"; + }, + options => Configuration.Bind(sectionName, options)); services.AddControllers(); services.AddAuthorization(options => diff --git a/tests/WebAppCallsWebApiCallsGraph/TodoListService/Startup.cs b/tests/WebAppCallsWebApiCallsGraph/TodoListService/Startup.cs index be7d25da6..7d2056a8c 100644 --- a/tests/WebAppCallsWebApiCallsGraph/TodoListService/Startup.cs +++ b/tests/WebAppCallsWebApiCallsGraph/TodoListService/Startup.cs @@ -32,7 +32,7 @@ public void ConfigureServices(IServiceCollection services) // Adds Microsoft Identity platform (AAD v2.0) support to protect this Api services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddProtectedWebApi("AzureAd", Configuration, options => Configuration.Bind("AzureAD", options)); + .AddProtectedWebApi(Configuration, "AzureAd"); services.AddControllers(); }