> serverFixture,
+ ITestOutputHelper output)
+ : base(browserFixture, serverFixture, output)
+ {
+ }
+
+ [Fact]
+ public void DoesNotSerializeAllClaimsByDefault()
+ {
+ Navigate($"{ServerPathBase}/auth/webassembly-interactive-authentication-state?roleClaimType=role&nameClaimType=name");
+
+ Browser.Click(By.LinkText("Log in"));
+
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive")).Text);
+ Browser.Equal("WebAssembly", () => Browser.FindElement(By.Id("platform")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
+ Browser.Equal("YourUsername", () => Browser.FindElement(By.Id("identity-name")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-1")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-2")).Text);
+
+ // While the name and role claims are serialized by default, the test claim is not.
+ Browser.Equal("(none)", () => Browser.FindElement(By.Id("test-claim")).Text);
+ }
+}
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/AuthTests/ServerRenderedAuthenticationStateTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/AuthTests/ServerRenderedAuthenticationStateTest.cs
index 378b146dd787..931b2368c241 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/AuthTests/ServerRenderedAuthenticationStateTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/AuthTests/ServerRenderedAuthenticationStateTest.cs
@@ -2,12 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.
using Components.TestServer.RazorComponents;
-using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
-using TestServer;
+using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
-using Xunit.Abstractions;
using OpenQA.Selenium;
+using TestServer;
+using Xunit.Abstractions;
namespace Microsoft.AspNetCore.Components.E2ETests.ServerRenderingTests.AuthTests;
@@ -20,46 +20,90 @@ public ServerRenderedAuthenticationStateTest(
ITestOutputHelper output)
: base(browserFixture, serverFixture, output)
{
+ // Test with AuthenticationStateSerializationOptions.SerializeAllClaims = true since that keeps the Server and WebAssembly
+ // behavior as similar as possible. The default behavior is tested by DefaultAuthenticationStateSerializationOptionsTest.
+ serverFixture.AdditionalArguments.Add("SerializeAllClaims=true");
+ }
+
+ [Theory]
+ [InlineData("Static")]
+ [InlineData("Server")]
+ [InlineData("WebAssembly")]
+ public void CanUseServerAuthenticationState(string platform)
+ {
+ var pageName = $"{platform}{(platform != "Static" ? "-interactive" : "")}-authentication-state";
+ Navigate($"{ServerPathBase}/auth/{pageName}");
+
+ VerifyLoggedOut(platform);
+
+ Browser.Click(By.LinkText("Log in"));
+
+ VerifyLoggedIn(platform);
+
+ Browser.Click(By.LinkText("Log out"));
+
+ VerifyLoggedOut(platform);
}
[Fact]
- public void CanUseServerAuthenticationState_Static()
+ public void CanUseCustomNameAndRoleTypeOnWebAssembly()
{
- Navigate($"{ServerPathBase}/auth/static-authentication-state");
+ Navigate($"{ServerPathBase}/auth/webassembly-interactive-authentication-state?roleClaimType=role&nameClaimType=name");
- Browser.Equal("False", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
- Browser.Equal("", () => Browser.FindElement(By.Id("identity-name")).Text);
- Browser.Equal("(none)", () => Browser.FindElement(By.Id("test-claim")).Text);
+ VerifyLoggedOut("WebAssembly");
Browser.Click(By.LinkText("Log in"));
- Browser.Equal("True", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
- Browser.Equal("YourUsername", () => Browser.FindElement(By.Id("identity-name")).Text);
- Browser.Equal("Test claim value", () => Browser.FindElement(By.Id("test-claim")).Text);
+ VerifyLoggedIn("WebAssembly");
+ Browser.Equal("(none)", () => Browser.FindElement(By.Id("additional-claim")).Text);
Browser.Click(By.LinkText("Log out"));
- Browser.Equal("False", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
+
+ VerifyLoggedOut("WebAssembly");
}
[Fact]
- public void CanUseServerAuthenticationState_Interactive()
+ public void CanCustomizeAuthenticationStateDeserialization()
{
- Navigate($"{ServerPathBase}/auth/interactive-authentication-state");
+ Navigate($"{ServerPathBase}/auth/webassembly-interactive-authentication-state?additionalClaim=Custom%20claim%20value");
+
+ VerifyLoggedOut("WebAssembly");
+ Browser.Equal("(none)", () => Browser.FindElement(By.Id("additional-claim")).Text);
+
+ Browser.Click(By.LinkText("Log in"));
+
+ VerifyLoggedIn("WebAssembly");
+ Browser.Equal("Custom claim value", () => Browser.FindElement(By.Id("additional-claim")).Text);
- Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive")).Text);
+ Browser.Click(By.LinkText("Log out"));
+
+ VerifyLoggedOut("WebAssembly");
+ Browser.Equal("(none)", () => Browser.FindElement(By.Id("additional-claim")).Text);
+ }
+
+ private void VerifyPlatform(string platform)
+ {
+ Browser.Equal((platform != "Static").ToString(), () => Browser.FindElement(By.Id("is-interactive")).Text);
+ Browser.Equal(platform, () => Browser.FindElement(By.Id("platform")).Text);
+ }
+
+ private void VerifyLoggedOut(string platform)
+ {
+ VerifyPlatform(platform);
Browser.Equal("False", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
Browser.Equal("", () => Browser.FindElement(By.Id("identity-name")).Text);
Browser.Equal("(none)", () => Browser.FindElement(By.Id("test-claim")).Text);
+ Browser.Equal("False", () => Browser.FindElement(By.Id("is-in-test-role-1")).Text);
+ Browser.Equal("False", () => Browser.FindElement(By.Id("is-in-test-role-2")).Text);
+ }
- Browser.Click(By.LinkText("Log in"));
-
- Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive")).Text);
+ private void VerifyLoggedIn(string platform)
+ {
+ VerifyPlatform(platform);
Browser.Equal("True", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
Browser.Equal("YourUsername", () => Browser.FindElement(By.Id("identity-name")).Text);
Browser.Equal("Test claim value", () => Browser.FindElement(By.Id("test-claim")).Text);
-
- Browser.Click(By.LinkText("Log out"));
- Browser.Equal("True", () => Browser.FindElement(By.Id("is-interactive")).Text);
- Browser.Equal("False", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-1")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-2")).Text);
}
}
diff --git a/src/Components/test/E2ETest/ServerRenderingTests/NoInteractivityTest.cs b/src/Components/test/E2ETest/ServerRenderingTests/NoInteractivityTest.cs
index 2a10978617cd..b0f887da31df 100644
--- a/src/Components/test/E2ETest/ServerRenderingTests/NoInteractivityTest.cs
+++ b/src/Components/test/E2ETest/ServerRenderingTests/NoInteractivityTest.cs
@@ -5,7 +5,6 @@
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Components.E2ETest.Infrastructure.ServerFixtures;
using Microsoft.AspNetCore.E2ETesting;
-using Microsoft.AspNetCore.InternalTesting;
using OpenQA.Selenium;
using TestServer;
using Xunit.Abstractions;
@@ -41,4 +40,27 @@ public void NavigationManagerCanRefreshSSRPageWhenInteractivityNotPresent()
Browser.NotEqual(guid, () => Browser.Exists(By.Id("guid")).Text);
Browser.Equal("GET", () => Browser.Exists(By.Id("method")).Text);
}
+
+ [Fact]
+ public void CanUseServerAuthenticationStateByDefault()
+ {
+ Navigate($"{ServerPathBase}/auth/static-authentication-state");
+
+ Browser.Equal("False", () => Browser.FindElement(By.Id("is-interactive")).Text);
+ Browser.Equal("Static", () => Browser.FindElement(By.Id("platform")).Text);
+
+ Browser.Equal("False", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
+ Browser.Equal("", () => Browser.FindElement(By.Id("identity-name")).Text);
+ Browser.Equal("(none)", () => Browser.FindElement(By.Id("test-claim")).Text);
+ Browser.Equal("False", () => Browser.FindElement(By.Id("is-in-test-role-1")).Text);
+ Browser.Equal("False", () => Browser.FindElement(By.Id("is-in-test-role-2")).Text);
+
+ Browser.Click(By.LinkText("Log in"));
+
+ Browser.Equal("True", () => Browser.FindElement(By.Id("identity-authenticated")).Text);
+ Browser.Equal("YourUsername", () => Browser.FindElement(By.Id("identity-name")).Text);
+ Browser.Equal("Test claim value", () => Browser.FindElement(By.Id("test-claim")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-1")).Text);
+ Browser.Equal("True", () => Browser.FindElement(By.Id("is-in-test-role-2")).Text);
+ }
}
diff --git a/src/Components/test/testassets/BasicTestApp/AuthTest/CascadingAuthenticationStateConsumer.razor b/src/Components/test/testassets/BasicTestApp/AuthTest/CascadingAuthenticationStateConsumer.razor
index 48852bf72908..1cc0035b7f4f 100644
--- a/src/Components/test/testassets/BasicTestApp/AuthTest/CascadingAuthenticationStateConsumer.razor
+++ b/src/Components/test/testassets/BasicTestApp/AuthTest/CascadingAuthenticationStateConsumer.razor
@@ -1,48 +1,4 @@
@page "/CascadingAuthenticationStateConsumer"
-@using System.Security.Claims
-@using Microsoft.AspNetCore.Components.Authorization
+@using TestContentPackage
-Cascading authentication state
-
-@if (user == null)
-{
- Requesting authentication state...
-}
-else
-{
-
- Authenticated:
- @user.Identity.IsAuthenticated
-
-
-
- Name:
- @user.Identity.Name
-
-
-
- Test claim:
- @if (user.HasClaim(TestClaimPredicate) == true)
- {
- @user.Claims.Single(c => TestClaimPredicate(c)).Value
- }
- else
- {
- (none)
- }
-
-}
-
-@code
-{
- static Predicate TestClaimPredicate = c => c.Type == "test-claim";
-
- ClaimsPrincipal user;
-
- [CascadingParameter] Task AuthenticationStateTask { get; set; }
-
- protected override async Task OnParametersSetAsync()
- {
- user = (await AuthenticationStateTask).User;
- }
-}
+
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsNoInteractivityStartup.cs b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsNoInteractivityStartup.cs
index 00c9fe461b31..c4af233c40fe 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsNoInteractivityStartup.cs
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsNoInteractivityStartup.cs
@@ -31,6 +31,7 @@ public void ConfigureServices(IServiceCollection services)
options.MaxFormMappingCollectionSize = 100;
});
services.AddHttpContextAccessor();
+ services.AddCascadingAuthenticationState();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
@@ -54,6 +55,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseStaticFiles();
app.UseRouting();
+ RazorComponentEndpointsStartup.UseFakeAuthState(app);
app.UseAntiforgery();
app.UseEndpoints(endpoints =>
{
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs
index 04d13dbf835f..7a9463136a36 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponentEndpointsStartup.cs
@@ -33,7 +33,13 @@ public void ConfigureServices(IServiceCollection services)
options.MaxFormMappingCollectionSize = 100;
})
.AddInteractiveWebAssemblyComponents()
- .AddInteractiveServerComponents();
+ .AddInteractiveServerComponents()
+ .AddAuthenticationStateSerialization(options =>
+ {
+ bool.TryParse(Configuration["SerializeAllClaims"], out var serializeAllClaims);
+ options.SerializeAllClaims = serializeAllClaims;
+ });
+
services.AddHttpContextAccessor();
services.AddSingleton();
services.AddCascadingAuthenticationState();
@@ -103,18 +109,21 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
});
}
- private static void UseFakeAuthState(IApplicationBuilder app)
+ internal static void UseFakeAuthState(IApplicationBuilder app)
{
app.Use((HttpContext context, Func next) =>
{
// Completely insecure fake auth system with no password for tests. Do not do anything like this in real apps.
// It accepts a query parameter 'username' and then sets or deletes a cookie to hold that, and supplies a principal
// using this username (taken either from the cookie or query param).
+ string GetQueryOrDefault(string queryKey, string defaultValue) =>
+ context.Request.Query.TryGetValue(queryKey, out var value) ? value : defaultValue;
+
const string cookieKey = "fake_username";
- context.Request.Cookies.TryGetValue(cookieKey, out var username);
- if (context.Request.Query.TryGetValue("username", out var usernameFromQuery))
+ var username = GetQueryOrDefault("username", context.Request.Cookies[cookieKey]);
+
+ if (context.Request.Query.ContainsKey("username"))
{
- username = usernameFromQuery;
if (string.IsNullOrEmpty(username))
{
context.Response.Cookies.Delete(cookieKey);
@@ -126,15 +135,20 @@ private static void UseFakeAuthState(IApplicationBuilder app)
}
}
+ var nameClaimType = GetQueryOrDefault("nameClaimType", ClaimTypes.Name);
+ var roleClaimType = GetQueryOrDefault("roleClaimType", ClaimTypes.Role);
+
if (!string.IsNullOrEmpty(username))
{
var claims = new List
{
- new Claim(ClaimTypes.Name, username),
+ new Claim(nameClaimType, username),
+ new Claim(roleClaimType, "test-role-1"),
+ new Claim(roleClaimType, "test-role-2"),
new Claim("test-claim", "Test claim value"),
};
- context.User = new ClaimsPrincipal(new ClaimsIdentity(claims, "FakeAuthenticationType"));
+ context.User = new ClaimsPrincipal(new ClaimsIdentity(claims, "FakeAuthenticationType", nameClaimType, roleClaimType));
}
return next();
diff --git a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
index 094bb249394f..717f269eb2fb 100644
--- a/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
+++ b/src/Components/test/testassets/Components.TestServer/RazorComponents/App.razor
@@ -18,14 +18,19 @@