From 296a80603501d1c4933d8c703ce765603411d123 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Mon, 16 Mar 2020 10:15:04 -0700 Subject: [PATCH 1/7] Cleanup startup apis --- ...lWebAssemblyServiceCollectionExtensions.cs | 18 +++-- ...thenticationServiceCollectionExtensions.cs | 73 ++++++++++++++----- 2 files changed, 66 insertions(+), 25 deletions(-) diff --git a/src/Components/WebAssembly/Authentication.Msal/src/MsalWebAssemblyServiceCollectionExtensions.cs b/src/Components/WebAssembly/Authentication.Msal/src/MsalWebAssemblyServiceCollectionExtensions.cs index 0071f2b758a3..2d395058fc38 100644 --- a/src/Components/WebAssembly/Authentication.Msal/src/MsalWebAssemblyServiceCollectionExtensions.cs +++ b/src/Components/WebAssembly/Authentication.Msal/src/MsalWebAssemblyServiceCollectionExtensions.cs @@ -23,15 +23,23 @@ public static class MsalWebAssemblyServiceCollectionExtensions /// The to configure the . /// The . public static IServiceCollection AddMsalAuthentication(this IServiceCollection services, Action> configure) + { + return AddMsalAuthentication(services, configure); + } + + /// + /// Adds authentication using msal.js to Blazor applications. + /// + /// The type of the remote authentication state. + /// The . + /// The to configure the . + /// The . + public static IServiceCollection AddMsalAuthentication(this IServiceCollection services, Action> configure) + where TRemoteAuthenticationState : RemoteAuthenticationState, new() { services.AddRemoteAuthentication(); services.TryAddEnumerable(ServiceDescriptor.Singleton>, MsalDefaultOptionsConfiguration>()); - if (configure != null) - { - services.Configure(configure); - } - return services; } } diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/WebAssemblyAuthenticationServiceCollectionExtensions.cs b/src/Components/WebAssembly/WebAssembly.Authentication/src/WebAssemblyAuthenticationServiceCollectionExtensions.cs index e8c2e8931080..352016df5bbb 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/WebAssemblyAuthenticationServiceCollectionExtensions.cs +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/WebAssemblyAuthenticationServiceCollectionExtensions.cs @@ -78,50 +78,83 @@ public static IServiceCollection AddRemoteAuthenticationThe where the services were registered. public static IServiceCollection AddOidcAuthentication(this IServiceCollection services, Action> configure) { - AddRemoteAuthentication(services, configure); + return AddOidcAuthentication(services, configure); + } + /// + /// Adds support for authentication for SPA applications using and the . + /// + /// The type of the remote authentication state. + /// The to add the services to. + /// An action that will configure the . + /// The where the services were registered. + public static IServiceCollection AddOidcAuthentication(this IServiceCollection services, Action> configure) + where TRemoteAuthenticationState : RemoteAuthenticationState, new() + { services.TryAddEnumerable(ServiceDescriptor.Singleton>, DefaultOidcOptionsConfiguration>()); - if (configure != null) - { - services.Configure(configure); - } - - return services; + return AddRemoteAuthentication(services, configure); } /// /// Adds support for authentication for SPA applications using and the . /// + /// The type of the remote authentication state. /// The to add the services to. /// The where the services were registered. public static IServiceCollection AddApiAuthorization(this IServiceCollection services) { - var inferredClientId = Assembly.GetCallingAssembly().GetName().Name; - - services.AddRemoteAuthentication(); - - services.TryAddEnumerable( - ServiceDescriptor.Singleton>, DefaultApiAuthorizationOptionsConfiguration>(_ => - new DefaultApiAuthorizationOptionsConfiguration(inferredClientId))); + return AddApiauthorizationCore(services, configure: null, Assembly.GetCallingAssembly().GetName().Name); + } - return services; + /// + /// Adds support for authentication for SPA applications using and the . + /// + /// The type of the remote authentication state. + /// The to add the services to. + /// The where the services were registered. + public static IServiceCollection AddApiAuthorization(this IServiceCollection services) + where TRemoteAuthenticationState : RemoteAuthenticationState, new() + { + return AddApiauthorizationCore(services, configure: null, Assembly.GetCallingAssembly().GetName().Name); } /// /// Adds support for authentication for SPA applications using and the . /// + /// The type of the remote authentication state. /// The to add the services to. /// An action that will configure the . /// The where the services were registered. public static IServiceCollection AddApiAuthorization(this IServiceCollection services, Action> configure) { - services.AddApiAuthorization(); + return AddApiauthorizationCore(services, configure, Assembly.GetCallingAssembly().GetName().Name); + } - if (configure != null) - { - services.Configure(configure); - } + /// + /// Adds support for authentication for SPA applications using and the . + /// + /// The type of the remote authentication state. + /// The to add the services to. + /// An action that will configure the . + /// The where the services were registered. + public static IServiceCollection AddApiAuthorization(this IServiceCollection services, Action> configure) + where TRemoteAuthenticationState : RemoteAuthenticationState, new() + { + return AddApiauthorizationCore(services, configure, Assembly.GetCallingAssembly().GetName().Name); + } + + private static IServiceCollection AddApiauthorizationCore( + IServiceCollection services, + Action> configure, + string inferredClientId) + where TRemoteAuthenticationState : RemoteAuthenticationState, new() + { + services.TryAddEnumerable( + ServiceDescriptor.Singleton>, DefaultApiAuthorizationOptionsConfiguration>(_ => + new DefaultApiAuthorizationOptionsConfiguration(inferredClientId))); + + services.AddRemoteAuthentication(configure); return services; } From ade8d3eac69d05758890b1788637b9e53ca40815 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Mon, 16 Mar 2020 10:32:16 -0700 Subject: [PATCH 2/7] Fix redirect to login --- .../ComponentsWebAssembly-CSharp/Client/App.razor | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/App.razor b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/App.razor index 9e038086aedf..c491110ce2b4 100644 --- a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/App.razor +++ b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/App.razor @@ -15,7 +15,14 @@ - + @if(!context.User.Identity.IsAuthenticated) + { + + } + else + { +

You are not authorized to access this resource.

+ }
From bdf6979f37f85983040295c42d5233c545bb6ef3 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Mon, 16 Mar 2020 10:49:51 -0700 Subject: [PATCH 3/7] Escape data string --- .../Client/Shared/RedirectToLogin.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/RedirectToLogin.razor b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/RedirectToLogin.razor index 7fa0d95bafe2..b535ae4216f2 100644 --- a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/RedirectToLogin.razor +++ b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Client/Shared/RedirectToLogin.razor @@ -3,6 +3,6 @@ @code { protected override void OnInitialized() { - Navigation.NavigateTo($"authentication/login?returnUrl={Navigation.Uri}"); + Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navigation.Uri)}"); } } From 59431492c78a0428a010c76cbf6718545099d2b4 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Mon, 16 Mar 2020 11:30:37 -0700 Subject: [PATCH 4/7] Fix async initialization bug --- .../src/Interop/AuthenticationService.ts | 19 +++++++++++++++---- .../src/Interop/package.json | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts index a0f6a9b3002b..919ee1d5e092 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/AuthenticationService.ts @@ -253,15 +253,26 @@ class OidcAuthorizeService implements AuthorizeService { export class AuthenticationService { static _infrastructureKey = 'Microsoft.AspNetCore.Components.WebAssembly.Authentication'; - static _initialized = false; + static _initialized : Promise; static instance: OidcAuthorizeService; public static async init(settings: UserManagerSettings & AuthorizeServiceSettings) { + // Multiple initializations can start concurrently and we want to avoid that. + // In order to do so, we create an initialization promise and the first call to init + // tries to initialize the app and sets up a promise other calls can await on. if (!AuthenticationService._initialized) { - AuthenticationService._initialized = true; - const userManager = await this.createUserManager(settings); - AuthenticationService.instance = new OidcAuthorizeService(userManager); + this._initialized = new Promise(async (resolve, reject) => { + try { + const userManager = await this.createUserManager(settings); + AuthenticationService.instance = new OidcAuthorizeService(userManager); + resolve(); + } catch (e) { + reject(e); + } + }); } + + await this._initialized; } public static getUser() { diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json index b0ae30371739..dd40f447edc6 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Interop/package.json @@ -1,4 +1,5 @@ { + "private": true, "scripts": { "build": "npm run build:release", "build:release": "webpack --mode production --env.production --env.configuration=Release", From fc4bc4ba9cc48d321c81be159a80e76b38a648d4 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Fri, 20 Mar 2020 08:51:50 -0700 Subject: [PATCH 5/7] Add metadata url --- .../src/Options/OidcProviderOptions.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Options/OidcProviderOptions.cs b/src/Components/WebAssembly/WebAssembly.Authentication/src/Options/OidcProviderOptions.cs index 9c1c74933ca4..56859689ed01 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Options/OidcProviderOptions.cs +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Options/OidcProviderOptions.cs @@ -16,6 +16,11 @@ public class OidcProviderOptions /// public string Authority { get; set; } + /// + /// Gets or sets the metadata url of the oidc provider. + /// + public string MetadataUrl { get; set; } + /// /// Gets or sets the client of the application. /// From eaecb5d1d2670c9e2d359a6fe4ec27d3728347d7 Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Fri, 20 Mar 2020 09:46:06 -0700 Subject: [PATCH 6/7] Update msal cache option --- .../Authentication.Msal/src/Models/MsalProviderOptions.cs | 7 ++++++- .../src/MsalDefaultOptionsConfiguration.cs | 5 ----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Components/WebAssembly/Authentication.Msal/src/Models/MsalProviderOptions.cs b/src/Components/WebAssembly/Authentication.Msal/src/Models/MsalProviderOptions.cs index 20af240d0502..8fa6b8b29249 100644 --- a/src/Components/WebAssembly/Authentication.Msal/src/Models/MsalProviderOptions.cs +++ b/src/Components/WebAssembly/Authentication.Msal/src/Models/MsalProviderOptions.cs @@ -24,7 +24,12 @@ public class MsalProviderOptions /// /// Gets or sets the msal.js cache options. /// - public MsalCacheOptions Cache { get; set; } + public MsalCacheOptions Cache { get; set; } = new MsalCacheOptions + { + // This matches the defaults in msal.js + CacheLocation = "sessionStorage", + StoreAuthStateInCookie = false + }; /// /// Gets or set the list of default access tokens scopes to provision during the sign-in flow. diff --git a/src/Components/WebAssembly/Authentication.Msal/src/MsalDefaultOptionsConfiguration.cs b/src/Components/WebAssembly/Authentication.Msal/src/MsalDefaultOptionsConfiguration.cs index b0dc7ffa0707..c98c6f871e82 100644 --- a/src/Components/WebAssembly/Authentication.Msal/src/MsalDefaultOptionsConfiguration.cs +++ b/src/Components/WebAssembly/Authentication.Msal/src/MsalDefaultOptionsConfiguration.cs @@ -40,11 +40,6 @@ public void Configure(RemoteAuthenticationOptions options) } options.ProviderOptions.Authentication.NavigateToLoginRequestUrl = false; - options.ProviderOptions.Cache = new MsalCacheOptions - { - CacheLocation = "localStorage", - StoreAuthStateInCookie = true - }; } public void PostConfigure(string name, RemoteAuthenticationOptions options) From ea7bec2478c4f7c651c7ea45520455af0252737c Mon Sep 17 00:00:00 2001 From: Javier Calvarro Nelson Date: Fri, 20 Mar 2020 11:16:36 -0700 Subject: [PATCH 7/7] Fix base path issue --- .../testassets/Wasm.Authentication.Server/Startup.cs | 2 +- .../content/ComponentsWebAssembly-CSharp/Server/Startup.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs index 56e6cb43e0d3..2a8f10d22585 100644 --- a/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs +++ b/src/Components/WebAssembly/testassets/Wasm.Authentication.Server/Startup.cs @@ -52,8 +52,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseRouting(); - app.UseAuthentication(); app.UseIdentityServer(); + app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => diff --git a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs index 7359cb33d108..3dfd09e9c5b0 100644 --- a/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs +++ b/src/ProjectTemplates/ComponentsWebAssembly.ProjectTemplates/content/ComponentsWebAssembly-CSharp/Server/Startup.cs @@ -107,12 +107,12 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseRouting(); -#if (OrganizationalAuth || IndividualAuth) - app.UseAuthentication(); -#endif #if (IndividualLocalAuth) app.UseIdentityServer(); #endif +#if (OrganizationalAuth || IndividualAuth) + app.UseAuthentication(); +#endif #if (!NoAuth) app.UseAuthorization();