fix(security): first-party JwtBearer with HS256 pinned; /auth/token mints for a cookie session only
The hand-rolled bearer handler is replaced by AddJwtBearer (Microsoft.AspNetCore.Authentication.JwtBearer 10.0.7, pinned on the same servicing line as the other AspNetCore packages). Validation parameters come from JwtTokenService.BuildValidationParameters, which now pins ValidAlgorithms = HS256 for both the bearer scheme and TryValidate; MapInboundClaims is off so the minted Role/zb:username keys resolve. /auth/token requires the cookie scheme, so a bearer can no longer mint a fresh token for itself. Refs #733 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -24,6 +24,17 @@ public static class AuthEndpoints
|
||||
/// <summary>Response for a token issue request.</summary>
|
||||
public sealed record TokenResponse(string Token);
|
||||
|
||||
/// <summary>
|
||||
/// The <c>/auth/token</c> policy: an authenticated principal from the COOKIE scheme. Naming the scheme
|
||||
/// makes the authorization middleware authenticate that scheme alone, so an <c>Authorization: Bearer</c>
|
||||
/// header is never consulted here (with login disabled the auto-login handler sits under the same
|
||||
/// scheme name, so the dev rig is unchanged).
|
||||
/// </summary>
|
||||
internal static readonly AuthorizationPolicy CookieSessionOnly =
|
||||
new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
|
||||
/// <summary>Maps OtOpcUa authentication endpoints to the application route builder.</summary>
|
||||
/// <param name="app">The endpoint route builder.</param>
|
||||
/// <returns>The endpoint route builder for chaining.</returns>
|
||||
@@ -40,7 +51,10 @@ public static class AuthEndpoints
|
||||
// Mapped only when a signing key is configured (JwtOptions.IsConfigured): an unconfigured
|
||||
// endpoint used to answer HTTP 500 from the JwtTokenService constructor on every call.
|
||||
if (app.ServiceProvider.GetRequiredService<IOptions<JwtOptions>>().Value.IsConfigured)
|
||||
app.MapPost("/auth/token", (Delegate)IssueToken).RequireAuthorization();
|
||||
// COOKIE scheme only (fix round 1 / I2): the default scheme also accepts a bearer, and a bearer
|
||||
// that could mint a fresh token would renew itself forever — outliving its own expiry and the
|
||||
// user's LDAP membership. A token is minted only for an interactive (cookie) session.
|
||||
app.MapPost("/auth/token", (Delegate)IssueToken).RequireAuthorization(CookieSessionOnly);
|
||||
else
|
||||
app.ServiceProvider.GetService<ILoggerFactory>()?
|
||||
.CreateLogger("ZB.MOM.WW.OtOpcUa.Security.AuthEndpoints")
|
||||
|
||||
Reference in New Issue
Block a user