fix(security): validate the API-key pepper at start, finish JWT bearer, circuit-aware audit actor
- ApiKeyOptionsValidator (ValidateOnStart on any driver/admin node): a blank or placeholder Security:ApiKeys:Pepper fails host start instead of rejecting every key after a green boot (R03:2.3). - JWT is finished and opt-in by key (R03:2.4): with Security:Jwt:SigningKey set, a Bearer scheme (JwtBearerAuthenticationHandler over JwtTokenService.TryValidate / BuildValidationParameters, fail closed) accepts the tokens /auth/token mints; the default scheme is a cookie-or-bearer policy scheme and the fallback policy names it, so /api/* and every RequireAuthorization endpoint take a browser session OR a machine token. JwtOptions are validated at start (JwtOptionsValidator). Without a key, /auth/token is not mapped (404, not the former constructor 500) and no bearer scheme exists. A direct AddJwtBearer needs Microsoft.AspNetCore.Authentication.JwtBearer in Directory.Packages.props (not this lane's file) — the handler is a drop-in to swap. - AuthenticationStateAuditActorAccessor is the registered IAuditActorAccessor: the Blazor circuit's principal first, HttpContext as the fallback (R03:2.5). HttpAuditActorAccessor shares its resolver. - CookieAuthenticationStateProvider (unregistered, fire-and-forget ping loop) is deleted (R03:1.5/2.5). - /auth/login logs the LDAP exception at Warning before answering 503 (R03:2.7). - Admin operations reply with a fixed message + correlation id instead of ex.Message (R03:4.1). Refs #733 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -162,10 +162,15 @@ builder.AddZbSerilog(o => o.ServiceName = "otopcua");
|
||||
// central over the fetch-and-cache path (ConfigSource:Mode=FetchAndCache). Registering it
|
||||
// unconditionally would throw on a driver-only node, since AddOtOpcUaConfigDb requires the string.
|
||||
// A fused admin+driver node keeps ConfigDb via its admin role — byte-for-byte unaffected.
|
||||
// bound unconditionally: a driver node needs the pepper to VERIFY keys, an admin node needs it
|
||||
// to MINT them, and getting this wrong on either side is a silent authentication failure rather than a
|
||||
// startup error.
|
||||
builder.Services.Configure<ApiKeyOptions>(builder.Configuration.GetSection(ApiKeyOptions.SectionName));
|
||||
// A driver node needs the pepper to VERIFY keys, an admin node needs it to MINT them, and getting this
|
||||
// wrong on either side used to be a silent authentication failure rather than a startup error (R03:2.3):
|
||||
// ApiKeyOptionsValidator now fails host start on a blank or placeholder pepper wherever either role is
|
||||
// present. A node with neither role (dev-only) has no key path and keeps the plain bind.
|
||||
if (hasDriver || hasAdmin)
|
||||
builder.Services.AddValidatedOptions<ApiKeyOptions, ApiKeyOptionsValidator>(
|
||||
builder.Configuration, ApiKeyOptions.SectionName);
|
||||
else
|
||||
builder.Services.Configure<ApiKeyOptions>(builder.Configuration.GetSection(ApiKeyOptions.SectionName));
|
||||
// Security:Acl:Enabled. Default false; see AclOptions for why the flip must be a config
|
||||
// change rather than a redeploy, and what it swaps rather than adds.
|
||||
builder.Services.Configure<AclOptions>(builder.Configuration.GetSection(AclOptions.SectionName));
|
||||
|
||||
Reference in New Issue
Block a user