fix(admin): resolve Medium code-review finding (Admin-006)
Emit <AntiforgeryToken /> in the MainLayout sign-out form and remove .DisableAntiforgery() from the /auth/logout endpoint so UseAntiforgery() validates the token. A tokenless POST now returns 400, preventing CSRF-logout. Regression-guarded by AuthEndpointsTests.Logout_without_antiforgery_token_is_rejected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -148,16 +148,19 @@ public sealed class AuthEndpointsTests : IClassFixture<AuthEndpointsTests.Stubbe
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Logout_endpoint_clears_the_cookie_and_redirects_to_login()
|
||||
public async Task Logout_without_antiforgery_token_is_rejected()
|
||||
{
|
||||
// Admin-006: the logout endpoint no longer calls .DisableAntiforgery(), so the
|
||||
// UseAntiforgery() middleware must reject a POST that carries no token with 400.
|
||||
// This regression guards against CSRF-logout (attacker tricking the browser into
|
||||
// signing the operator out by posting to /auth/logout from a foreign origin).
|
||||
using var client = _factory.CreateNonRedirectingClient();
|
||||
|
||||
var response = await client.PostAsync("/auth/logout",
|
||||
new FormUrlEncodedContent(Array.Empty<KeyValuePair<string, string>>()));
|
||||
|
||||
// No antiforgery 400 — the endpoint opts out (Admin-006 note in AuthEndpoints).
|
||||
response.StatusCode.ShouldBeOneOf(HttpStatusCode.Redirect, HttpStatusCode.Found);
|
||||
response.Headers.Location!.OriginalString.ShouldContain("/login");
|
||||
response.StatusCode.ShouldBe(HttpStatusCode.BadRequest,
|
||||
"/auth/logout without an antiforgery token must be rejected (Admin-006)");
|
||||
}
|
||||
|
||||
// ── Admin-003: SignalR hubs reject anonymous connections ────────────────────
|
||||
|
||||
Reference in New Issue
Block a user