4.3 KiB
4.3 KiB
SEC-005B email ownership verification
Date: 2026-08-02
Status: IMPLEMENTED — NOT VERIFIED. Backend, frontend component, build, migration-script and isolated API runtime checks pass. Required real-browser, SMTP-link and production/MariaDB execution checks remain blocked.
Implemented contract
- Registration with
Auth:RequireEmailVerification=truereturns HTTP 202 with{ "verificationRequired": true }, creates noUserSession, and emits no auth/CSRF cookie. - Existing unconfirmed sessions are rejected by local session validation while verification is required.
- Generic profile updates no longer mutate
ApplicationUser.Email. - Local accounts request a new address with their current password. The active address remains unchanged and both current and proposed addresses receive non-secret notifications.
PendingEmail,PendingEmailRequestedAtUtc, and a rotated security stamp make replacement requests invalidate older Identity change-email tokens.- Confirmation accepts only the current pending address, uses
UserManager.ChangeEmailAsync, updates username only when it still tracks the old email, clears pending state, and revokes all sessions/trusted devices. - Cancellation requires the current password and clears pending state.
- ASP.NET Identity default token providers are registered; data-protection keys already persist under
Data:Root/keys.
Evidence
- Focused backend auth/revocation tests: 35/35 passed.
- Full backend suite: 501/501 passed.
- Full frontend suite: 43 suites, 151/151 tests passed.
- Frontend production build: passed.
- SQLite migration script:
PendingEmail TEXT,PendingEmailRequestedAtUtc TEXT. - MariaDB migration script:
PendingEmail varchar(320),PendingEmailRequestedAtUtc datetime(6). - Disposable SQLite upgrade rehearsal with earlier migrations marked applied: migration applied and both columns were present.
- Isolated API runtime, email disabled and synthetic address only:
- registration returned 202 and
verificationRequired=true; - no
Set-Cookieheader and zero client cookies; - immediate login returned 403
email_not_verifiedand still zero cookies.
- registration returned 202 and
- No email was sent and no production service or database was contacted.
Blocked or partial checks
- The in-app browser denied localhost because its admin policy check was unavailable. No workflow is labeled browser-tested; desktop/mobile/keyboard and visible confirmation checks remain.
- A fresh empty SQLite migration rehearsal failed in the pre-existing
AddJobEntityAndProspectStagesmigration becauseLastReminderEmailSentAtis absent. SEC-005B's migration was not reached. The matching upgrade rehearsal passed; CORE-001 owns the broken fresh chain. - MariaDB SQL generation passed, but no disposable MariaDB instance was available for execution.
- SMTP resend/request/confirm links and production version-skew remain unverified.
- The execution policy rejected cleanup of
C:\Users\Cesnimda\AppData\Local\Temp\jobtracker-sec005b-browser-20260802. It contains only disposable synthetic runtime data and local data-protection material; no process is using it.
Commands
dotnet ef --version
dotnet ef migrations add AddPendingEmailChange --project JobTrackerApi/JobTrackerApi.csproj --startup-project JobTrackerApi/JobTrackerApi.csproj --no-build
dotnet build JobTrackerApi/JobTrackerApi.csproj --no-restore
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --no-restore --filter "FullyQualifiedName~AuthAndSystemControllerTests|FullyQualifiedName~AuthSessionRevocationTests"
dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --no-restore
npm run build
npm test -- --runInBand
dotnet ef migrations script 20260731115022_AddStripeBillingState 20260802205800_AddPendingEmailChange ...
dotnet ef database update ... (disposable SQLite fresh and upgrade rehearsals)
dotnet run --no-build --no-launch-profile --project JobTrackerApi/JobTrackerApi.csproj --urls http://127.0.0.1:5302
Remaining acceptance checks
- Real-browser registration, resend, verification, email request, cancellation and confirmation using a local email sink.
- Expired/replayed real Identity token integration check and custom-username preservation integration check.
- Disposable MariaDB upgrade/rollback execution.
- Production SMTP/canonical-origin and rolling-version smoke with synthetic addresses.