c68b49eda0
Adds three layers of account-security hardening, all gated behind the existing SignInWithAppSessionAsync-equivalent (now AppSessionIssuer) so every sign-in path -- local, Google, Microsoft -- goes through the same lockout/2FA checks: - Per-account lockout: Identity's built-in lockout store (columns already provisioned, previously unused) is now wired up in AuthController.Login via IsLockedOutAsync/AccessFailedAsync/ResetAccessFailedCountAsync, 5 failed attempts / 15 min, same generic 401 as wrong-password to avoid enumeration. - RFC 6238 TOTP 2FA (Otp.NET) with QR-code setup (QRCoder, fully local/ offline) on a new TwoFactorController: setup requires password re-confirmation and returns a pending (unconfirmed) secret + QR; the secret is only persisted as active once verify-setup checks a real code. Secrets are encrypted at rest via the same IDataProtector pattern already used for Gmail/Microsoft OAuth refresh tokens. - Login/OAuth exchange now checks TwoFactorEnabled before issuing a real session. If enabled, it hands back an opaque, server-side (IMemoryCache) pending token via a new ITwoFactorPendingTokenService -- deliberately NOT a JWT, so it can never be presented as a bearer token to bypass the 2FA check on any other endpoint. Only POST /api/auth/2fa/challenge can redeem it, rate-limited at 5/5min (tighter than password login, since a 6-digit space is far more brute-forceable). - One-time recovery codes (10 per enable/regenerate, SHA-256-hashed at rest, shown once in plaintext) accepted in the same challenge endpoint as an alternative to a TOTP code. Schema: AspNetUsers gains TotpSecretEncrypted / TotpPendingSecretEncrypted / TotpEnabledAtUtc, plus a new TwoFactorRecoveryCodes table, added to both the SQLite and MySQL dialect blocks in the startup schema reconciler. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
37 lines
1.7 KiB
XML
37 lines
1.7 KiB
XML
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
<!--
|
|
Transitional shared-backend project.
|
|
The API host and test project both reference this library so controller/service code can
|
|
be exercised without dragging the web-entry project into every test build.
|
|
Files still live in their original folders for now; a later refactor can move them physically.
|
|
-->
|
|
<PropertyGroup>
|
|
<TargetFramework>net9.0</TargetFramework>
|
|
<ImplicitUsings>enable</ImplicitUsings>
|
|
<Nullable>enable</Nullable>
|
|
<RestoreIgnoreFailedSources>true</RestoreIgnoreFailedSources>
|
|
<OutputType>Library</OutputType>
|
|
</PropertyGroup>
|
|
|
|
<ItemGroup>
|
|
<Compile Include="..\Data\**\*.cs" />
|
|
<Compile Include="..\Models\**\*.cs" />
|
|
<Compile Include="..\JobTrackerApi\Controllers\**\*.cs" />
|
|
<Compile Include="..\JobTrackerApi\Services\**\*.cs" />
|
|
</ItemGroup>
|
|
|
|
<ItemGroup>
|
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.14" />
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.14">
|
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
<PrivateAssets>all</PrivateAssets>
|
|
</PackageReference>
|
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.14" />
|
|
<PackageReference Include="Otp.NET" Version="1.4.1" />
|
|
<PackageReference Include="QRCoder" Version="1.8.0" />
|
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.14.0" />
|
|
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="8.14.0" />
|
|
<PackageReference Include="MailKit" Version="4.17.0" />
|
|
</ItemGroup>
|
|
</Project>
|