From 1d59a11bf226c0e9cc5077f18d9f391c3a501498 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Mon, 26 Feb 2024 08:51:13 -0800 Subject: [PATCH 1/3] Preserve RemoteAuthenticationContext during JS interop --- .../src/Services/RemoteAuthenticationService.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs b/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs index 62d9fa5265e4..12d315bdaf60 100644 --- a/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs +++ b/src/Components/WebAssembly/WebAssembly.Authentication/src/Services/RemoteAuthenticationService.cs @@ -108,7 +108,7 @@ public virtual async Task RemoteAuthenticationContext context) { await EnsureAuthService(); - var result = await JsRuntime.InvokeAsync>("AuthenticationService.signIn", context); + var result = await JSInvokeWithContextAsync, RemoteAuthenticationResult>("AuthenticationService.signIn", context); await UpdateUserOnSuccess(result); return result; @@ -130,7 +130,7 @@ public virtual async Task RemoteAuthenticationContext context) { await EnsureAuthService(); - var result = await JsRuntime.InvokeAsync>("AuthenticationService.signOut", context); + var result = await JSInvokeWithContextAsync, RemoteAuthenticationResult>("AuthenticationService.signOut", context); await UpdateUserOnSuccess(result); return result; @@ -187,6 +187,11 @@ public virtual async ValueTask RequestAccessToken(AccessToken } : null); } + // JSRuntime.InvokeAsync does not properly annotate all arguments with DynamicallyAccessedMembersAttribute. https://github.com/dotnet/aspnetcore/issues/39839 + // Calling JsRuntime.InvokeAsync directly results allows the RemoteAuthenticationContext.State getter to be trimmed. https://github.com/dotnet/aspnetcore/issues/49956 + private ValueTask JSInvokeWithContextAsync<[DynamicallyAccessedMembers(JsonSerialized)] TContext, [DynamicallyAccessedMembers(JsonSerialized)] TResult>( + string identifier, TContext context) => JsRuntime.InvokeAsync(identifier, context); + private string GetReturnUrl(string? customReturnUrl) => customReturnUrl != null ? Navigation.ToAbsoluteUri(customReturnUrl).AbsoluteUri : Navigation.Uri; From 85e61c5e9b111330a0104522c7211b7d95fc5bdd Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Mon, 18 Mar 2024 16:07:00 -0700 Subject: [PATCH 2/3] Add trimmed E2E RemoteAuthenticationTest --- AspNetCore.sln | 38 ++++++++ src/Components/Components.slnf | 3 +- .../ServerFixtures/AspNetSiteServerFixture.cs | 2 +- ...soft.AspNetCore.Components.E2ETests.csproj | 9 +- .../E2ETest/Tests/RemoteAuthenticationTest.cs | 79 +++++++++++++++ .../Tests/WebAssemblyPrerenderedTest.cs | 2 +- .../Components.TestServer.csproj | 2 + .../Components.TestServer/Program.cs | 1 + .../RemoteAuthenticationApp.razor | 24 +++++ .../RemoteAuthenticationStartup.cs | 97 +++++++++++++++++++ ...Components.WasmRemoteAuthentication.csproj | 20 ++++ .../Pages/Authentication.razor | 9 ++ .../Pages/TestRemoteAuthentication.razor | 13 +++ .../Program.cs | 12 +++ .../Properties/launchSettings.json | 21 ++++ .../RedirectToLogin.razor | 14 +++ .../Routes.razor | 27 ++++++ 17 files changed, 368 insertions(+), 5 deletions(-) create mode 100644 src/Components/test/E2ETest/Tests/RemoteAuthenticationTest.cs create mode 100644 src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor create mode 100644 src/Components/test/testassets/Components.TestServer/RemoteAuthenticationStartup.cs create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Components.WasmRemoteAuthentication.csproj create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/Authentication.razor create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/TestRemoteAuthentication.razor create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Program.cs create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Properties/launchSettings.json create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/RedirectToLogin.razor create mode 100644 src/Components/test/testassets/Components.WasmRemoteAuthentication/Routes.razor diff --git a/AspNetCore.sln b/AspNetCore.sln index 60a610ed33f6..64fcd4dc45b4 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -1786,6 +1786,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Intern EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotReferencedInWasmCodePackage", "src\Components\test\testassets\NotReferencedInWasmCodePackage\NotReferencedInWasmCodePackage.csproj", "{433F91E4-E39D-4EB0-B798-2998B3969A2C}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuth", "src\Components\test\testassets\Components.WasmRemoteAuth\Components.WasmRemoteAuth.csproj", "{D2848C1B-4962-4B94-AC5F-A3C368C5B351}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuthentication", "src\Components\test\testassets\Components.WasmRemoteAuthentication\Components.WasmRemoteAuthentication.csproj", "{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -10771,6 +10775,38 @@ Global {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x64.Build.0 = Release|Any CPU {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x86.ActiveCfg = Release|Any CPU {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x86.Build.0 = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|arm64.ActiveCfg = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|arm64.Build.0 = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x64.ActiveCfg = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x64.Build.0 = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x86.ActiveCfg = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x86.Build.0 = Debug|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|Any CPU.Build.0 = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|arm64.ActiveCfg = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|arm64.Build.0 = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x64.ActiveCfg = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x64.Build.0 = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x86.ActiveCfg = Release|Any CPU + {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x86.Build.0 = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|arm64.ActiveCfg = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|arm64.Build.0 = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|x64.ActiveCfg = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|x64.Build.0 = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|x86.ActiveCfg = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|x86.Build.0 = Debug|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|Any CPU.Build.0 = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|arm64.ActiveCfg = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|arm64.Build.0 = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x64.ActiveCfg = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x64.Build.0 = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x86.ActiveCfg = Release|Any CPU + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -11653,6 +11689,8 @@ Global {B0A8E5D4-BC5A-448E-B222-431B6B2EB58E} = {05A169C7-4F20-4516-B10A-B13C5649D346} {15D08EA7-8C63-45FB-8B4D-C5F8E43B433E} = {05A169C7-4F20-4516-B10A-B13C5649D346} {433F91E4-E39D-4EB0-B798-2998B3969A2C} = {6126DCE4-9692-4EE2-B240-C65743572995} + {D2848C1B-4962-4B94-AC5F-A3C368C5B351} = {6126DCE4-9692-4EE2-B240-C65743572995} + {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13} = {6126DCE4-9692-4EE2-B240-C65743572995} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3E8720B3-DBDD-498C-B383-2CC32A054E8F} diff --git a/src/Components/Components.slnf b/src/Components/Components.slnf index a6d8e9a7b8e2..1f0cfe428c19 100644 --- a/src/Components/Components.slnf +++ b/src/Components/Components.slnf @@ -35,8 +35,8 @@ "src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Client\\HostedInAspNet.Client.csproj", "src\\Components\\WebAssembly\\testassets\\HostedInAspNet.Server\\HostedInAspNet.Server.csproj", "src\\Components\\WebAssembly\\testassets\\StandaloneApp\\StandaloneApp.csproj", - "src\\Components\\WebAssembly\\testassets\\ThreadingApp\\ThreadingApp.csproj", "src\\Components\\WebAssembly\\testassets\\ThreadingApp.Server\\ThreadingApp.Server.csproj", + "src\\Components\\WebAssembly\\testassets\\ThreadingApp\\ThreadingApp.csproj", "src\\Components\\WebAssembly\\testassets\\Wasm.Prerendered.Client\\Wasm.Prerendered.Client.csproj", "src\\Components\\WebAssembly\\testassets\\Wasm.Prerendered.Server\\Wasm.Prerendered.Server.csproj", "src\\Components\\WebAssembly\\testassets\\WasmLinkerTest\\WasmLinkerTest.csproj", @@ -54,6 +54,7 @@ "src\\Components\\test\\testassets\\BasicTestApp\\BasicTestApp.csproj", "src\\Components\\test\\testassets\\Components.TestServer\\Components.TestServer.csproj", "src\\Components\\test\\testassets\\Components.WasmMinimal\\Components.WasmMinimal.csproj", + "src\\Components\\test\\testassets\\Components.WasmRemoteAuthentication\\Components.WasmRemoteAuthentication.csproj", "src\\Components\\test\\testassets\\ComponentsApp.App\\ComponentsApp.App.csproj", "src\\Components\\test\\testassets\\ComponentsApp.Server\\ComponentsApp.Server.csproj", "src\\Components\\test\\testassets\\GlobalizationWasmApp\\GlobalizationWasmApp.csproj", diff --git a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs index e39b3b8ffcf5..bd51576b15fe 100644 --- a/src/Components/test/E2ETest/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs +++ b/src/Components/test/E2ETest/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs @@ -35,7 +35,7 @@ protected override IHost CreateWebHost() } var assembly = ApplicationAssembly ?? BuildWebHostMethod.Method.DeclaringType.Assembly; - var sampleSitePath = DefaultGetContentRoot(assembly); + var sampleSitePath = GetContentRootMethod(assembly); var host = "127.0.0.1"; if (E2ETestOptions.Instance.SauceTest) diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index f2b35f3f0699..a5ee39d50f48 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -1,4 +1,4 @@ - + diff --git a/src/Components/test/E2ETest/Tests/RemoteAuthenticationTest.cs b/src/Components/test/E2ETest/Tests/RemoteAuthenticationTest.cs new file mode 100644 index 000000000000..6915b0915198 --- /dev/null +++ b/src/Components/test/E2ETest/Tests/RemoteAuthenticationTest.cs @@ -0,0 +1,79 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Reflection; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure; +using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures; +using Microsoft.AspNetCore.E2ETesting; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Testing; +using OpenQA.Selenium; +using TestServer; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Components.E2ETest.Tests; + +public class RemoteAuthenticationTest : + ServerTestBase> +{ + public readonly bool TestTrimmedApps = typeof(ToggleExecutionModeServerFixture<>).Assembly + .GetCustomAttributes() + .First(m => m.Key == "Microsoft.AspNetCore.E2ETesting.TestTrimmedOrMultithreadingApps") + .Value == "true"; + + public RemoteAuthenticationTest( + BrowserFixture browserFixture, + BasicTestAppServerSiteFixture serverFixture, + ITestOutputHelper output) + : base(browserFixture, serverFixture, output) + { + serverFixture.ApplicationAssembly = typeof(RemoteAuthenticationStartup).Assembly; + + if (TestTrimmedApps) + { + serverFixture.BuildWebHostMethod = BuildPublishedWebHost; + serverFixture.GetContentRootMethod = GetPublishedContentRoot; + } + } + + [Fact] + public void NavigateToLogin_PreservesExtraQueryParams() + { + // If the preservedExtraQueryParams passed to NavigateToLogin by RedirectToLogin gets trimmed, + // the OIDC endpoints will fail to authenticate the user. + Navigate("/subdir/test-remote-authentication"); + + var heading = Browser.Exists(By.TagName("h1")); + Browser.Equal("Hello, Jane Doe!", () => heading.Text); + } + + private static IHost BuildPublishedWebHost(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureLogging((ctx, lb) => + { + TestSink sink = new TestSink(); + lb.AddProvider(new TestLoggerProvider(sink)); + lb.Services.AddSingleton(sink); + }) + .ConfigureWebHostDefaults(webHostBuilder => + { + webHostBuilder.UseStartup(); + // Avoid UseStaticAssets or we won't use the trimmed published output. + }) + .Build(); + + private static string GetPublishedContentRoot(Assembly assembly) + { + var contentRoot = Path.Combine(AppContext.BaseDirectory, "trimmed-or-threading", assembly.GetName().Name); + + if (!Directory.Exists(contentRoot)) + { + throw new DirectoryNotFoundException($"Test is configured to use trimmed outputs, but trimmed outputs were not found in {contentRoot}."); + } + + return contentRoot; + } +} diff --git a/src/Components/test/E2ETest/Tests/WebAssemblyPrerenderedTest.cs b/src/Components/test/E2ETest/Tests/WebAssemblyPrerenderedTest.cs index 189bb71719a1..6c54fcd1c56a 100644 --- a/src/Components/test/E2ETest/Tests/WebAssemblyPrerenderedTest.cs +++ b/src/Components/test/E2ETest/Tests/WebAssemblyPrerenderedTest.cs @@ -56,7 +56,7 @@ private void WaitUntilLoaded() private static string GetPublishedContentRoot(Assembly assembly) { - var contentRoot = Path.Combine(AppContext.BaseDirectory, "trimmed", assembly.GetName().Name); + var contentRoot = Path.Combine(AppContext.BaseDirectory, "trimmed-or-threading", assembly.GetName().Name); if (!Directory.Exists(contentRoot)) { diff --git a/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj b/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj index 42e3895d1061..405a26d27291 100644 --- a/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj +++ b/src/Components/test/testassets/Components.TestServer/Components.TestServer.csproj @@ -28,11 +28,13 @@ + + diff --git a/src/Components/test/testassets/Components.TestServer/Program.cs b/src/Components/test/testassets/Components.TestServer/Program.cs index 16d5a35b81d2..0c3367d21480 100644 --- a/src/Components/test/testassets/Components.TestServer/Program.cs +++ b/src/Components/test/testassets/Components.TestServer/Program.cs @@ -19,6 +19,7 @@ public static async Task Main(string[] args) var createIndividualHosts = new Dictionary { ["Client authentication"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), + ["Remote client authentication"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), ["Server authentication"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), ["CORS (WASM)"] = (BuildWebHost(CreateAdditionalArgs(args)), "/subdir"), ["Prerendering (Server-side)"] = (BuildWebHost(CreateAdditionalArgs(args)), "/prerendered"), diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor new file mode 100644 index 000000000000..7cec534aca44 --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/RemoteAuthenticationApp.razor @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/Components/test/testassets/Components.TestServer/RemoteAuthenticationStartup.cs b/src/Components/test/testassets/Components.TestServer/RemoteAuthenticationStartup.cs new file mode 100644 index 000000000000..69aca756bb9e --- /dev/null +++ b/src/Components/test/testassets/Components.TestServer/RemoteAuthenticationStartup.cs @@ -0,0 +1,97 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Globalization; +using System.Reflection; +using Components.TestServer.RazorComponents; +using Microsoft.AspNetCore.Mvc; +using Microsoft.IdentityModel.JsonWebTokens; +using Microsoft.IdentityModel.Tokens; + +namespace TestServer; + +public class RemoteAuthenticationStartup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddRazorComponents() + .AddInteractiveWebAssemblyComponents(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + app.Map("/subdir", app => + { + app.UseStaticFiles(); + app.UseRouting(); + app.UseAntiforgery(); + app.UseEndpoints(endpoints => + { + endpoints.MapRazorComponents() + .AddAdditionalAssemblies(Assembly.Load("Components.WasmRemoteAuthentication")) + .AddInteractiveWebAssemblyRenderMode(options => options.PathPrefix = "/WasmRemoteAuthentication"); + + var oidcEndpoints = endpoints.MapGroup("oidc"); + + // This is designed to test a single login at a time. + var issuer = ""; + oidcEndpoints.MapGet(".well-known/openid-configuration", (HttpRequest request, [FromHeader] string host) => + { + issuer = $"{(request.IsHttps ? "https" : "http")}://{host}"; + return Results.Json(new + { + issuer, + authorization_endpoint = $"{issuer}/subdir/oidc/authorize", + token_endpoint = $"{issuer}/subdir/oidc/token", + }); + }); + + var lastCode = ""; + oidcEndpoints.MapGet("authorize", (string redirect_uri, string? state, string? prompt, bool? preservedExtraQueryParams) => + { + // Require interaction so silent sign-in does not skip RedirectToLogin.razor. + if (prompt == "none") + { + return Results.Redirect($"{redirect_uri}?error=interaction_required&state={state}"); + } + + // Verify that the extra query parameters added by RedirectToLogin.razor are preserved. + if (preservedExtraQueryParams != true) + { + return Results.Redirect($"{redirect_uri}?error=invalid_request&error_description=extraQueryParams%20not%20preserved&state={state}"); + } + + lastCode = Random.Shared.Next().ToString(CultureInfo.InvariantCulture); + return Results.Redirect($"{redirect_uri}?code={lastCode}&state={state}"); + }); + + var jwtHandler = new JsonWebTokenHandler(); + oidcEndpoints.MapPost("token", ([FromForm] string code) => + { + if (string.IsNullOrEmpty(lastCode) && code != lastCode) + { + return Results.BadRequest("Bad code"); + } + + return Results.Json(new + { + token_type = "Bearer", + scope = "openid profile", + expires_in = 3600, + id_token = jwtHandler.CreateToken(new SecurityTokenDescriptor + { + Issuer = issuer, + Audience = "s6BhdRkqt3", + Claims = new Dictionary + { + ["sub"] = "248289761001", + ["name"] = "Jane Doe", + }, + }), + }); + }).DisableAntiforgery(); + }); + }); + } +} diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Components.WasmRemoteAuthentication.csproj b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Components.WasmRemoteAuthentication.csproj new file mode 100644 index 000000000000..3b44a098893d --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Components.WasmRemoteAuthentication.csproj @@ -0,0 +1,20 @@ + + + + $(DefaultNetCoreTargetFramework) + enable + enable + WasmRemoteAuthentication + + + + + <_BlazorBrotliCompressionLevel>NoCompression + + + + + + + + diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/Authentication.razor b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/Authentication.razor new file mode 100644 index 000000000000..9ec02f227154 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/Authentication.razor @@ -0,0 +1,9 @@ +@page "/authentication/{action}" + +@using Microsoft.AspNetCore.Components.WebAssembly.Authentication + + + +@code { + [Parameter] public string? Action { get; set; } +} diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/TestRemoteAuthentication.razor b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/TestRemoteAuthentication.razor new file mode 100644 index 000000000000..a5a7cf05ec31 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Pages/TestRemoteAuthentication.razor @@ -0,0 +1,13 @@ +@page "/test-remote-authentication" + +@using Microsoft.AspNetCore.Components.Authorization + + + +

Hello, @context.User.Identity?.Name!

+
+ + @* Do this rather than rely on the [Authorize] attribute to avoid endpoint routing. *@ + + +
diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Program.cs b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Program.cs new file mode 100644 index 000000000000..e8f99c23b6e4 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Program.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +builder.Services.AddOidcAuthentication(options => +{ + options.ProviderOptions.Authority = $"{builder.HostEnvironment.BaseAddress}oidc"; + options.ProviderOptions.ClientId = "s6BhdRkqt3"; + options.ProviderOptions.ResponseType = "code"; +}); + +await builder.Build().RunAsync(); diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Properties/launchSettings.json b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Properties/launchSettings.json new file mode 100644 index 000000000000..ab37532e31fb --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Properties/launchSettings.json @@ -0,0 +1,21 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5102", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "applicationUrl": "https://localhost:7293;http://localhost:5102", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/RedirectToLogin.razor b/src/Components/test/testassets/Components.WasmRemoteAuthentication/RedirectToLogin.razor new file mode 100644 index 000000000000..76739ecc85d4 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/RedirectToLogin.razor @@ -0,0 +1,14 @@ +@using Microsoft.AspNetCore.Components.WebAssembly.Authentication + +@inject NavigationManager Navigation + +@code { + protected override void OnInitialized() + { + var request = new InteractiveRequestOptions { Interaction = InteractionType.SignIn, ReturnUrl = Navigation.Uri }; + var extraQueryParams = new Dictionary { ["preservedExtraQueryParams"] = "true" }; + request.TryAddAdditionalParameter("extraQueryParams", extraQueryParams); + + Navigation.NavigateToLogin("authentication/login", request); + } +} diff --git a/src/Components/test/testassets/Components.WasmRemoteAuthentication/Routes.razor b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Routes.razor new file mode 100644 index 000000000000..b69e64ec3e62 --- /dev/null +++ b/src/Components/test/testassets/Components.WasmRemoteAuthentication/Routes.razor @@ -0,0 +1,27 @@ +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web + + + + + + + @if (context.User.Identity?.IsAuthenticated != true) + { + + } + else + { +

You are not authorized to access this resource.

+ } +
+
+ +
+ + Not found +

Sorry, there's nothing at this address.

+
+
+
From 21ba68e28d1511a53972f4a7d25a16b675ea0656 Mon Sep 17 00:00:00 2001 From: Stephen Halter Date: Tue, 19 Mar 2024 12:46:55 -0700 Subject: [PATCH 3/3] Remove deleted project from sln and fix test build --- AspNetCore.sln | 19 ------------------- ...soft.AspNetCore.Components.E2ETests.csproj | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) diff --git a/AspNetCore.sln b/AspNetCore.sln index 64fcd4dc45b4..68269bb213ca 100644 --- a/AspNetCore.sln +++ b/AspNetCore.sln @@ -1786,8 +1786,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNetCore.Intern EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotReferencedInWasmCodePackage", "src\Components\test\testassets\NotReferencedInWasmCodePackage\NotReferencedInWasmCodePackage.csproj", "{433F91E4-E39D-4EB0-B798-2998B3969A2C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuth", "src\Components\test\testassets\Components.WasmRemoteAuth\Components.WasmRemoteAuth.csproj", "{D2848C1B-4962-4B94-AC5F-A3C368C5B351}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Components.WasmRemoteAuthentication", "src\Components\test\testassets\Components.WasmRemoteAuthentication\Components.WasmRemoteAuthentication.csproj", "{8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}" EndProject Global @@ -10775,22 +10773,6 @@ Global {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x64.Build.0 = Release|Any CPU {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x86.ActiveCfg = Release|Any CPU {433F91E4-E39D-4EB0-B798-2998B3969A2C}.Release|x86.Build.0 = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|arm64.ActiveCfg = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|arm64.Build.0 = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x64.ActiveCfg = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x64.Build.0 = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x86.ActiveCfg = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Debug|x86.Build.0 = Debug|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|Any CPU.Build.0 = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|arm64.ActiveCfg = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|arm64.Build.0 = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x64.ActiveCfg = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x64.Build.0 = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x86.ActiveCfg = Release|Any CPU - {D2848C1B-4962-4B94-AC5F-A3C368C5B351}.Release|x86.Build.0 = Release|Any CPU {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|Any CPU.Build.0 = Debug|Any CPU {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13}.Debug|arm64.ActiveCfg = Debug|Any CPU @@ -11689,7 +11671,6 @@ Global {B0A8E5D4-BC5A-448E-B222-431B6B2EB58E} = {05A169C7-4F20-4516-B10A-B13C5649D346} {15D08EA7-8C63-45FB-8B4D-C5F8E43B433E} = {05A169C7-4F20-4516-B10A-B13C5649D346} {433F91E4-E39D-4EB0-B798-2998B3969A2C} = {6126DCE4-9692-4EE2-B240-C65743572995} - {D2848C1B-4962-4B94-AC5F-A3C368C5B351} = {6126DCE4-9692-4EE2-B240-C65743572995} {8A021D6D-7935-4AB3-BB47-38D4FF9B0D13} = {6126DCE4-9692-4EE2-B240-C65743572995} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index a5ee39d50f48..8e256261983c 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -48,6 +48,7 @@
+ @@ -60,7 +61,6 @@ -