Files

4.7 KiB

Email authentication implementation audit

Verified on 2026-09-09 against commit c452fc7 and the local production build 0.1.12-SNAPSHOT. This supersedes the historical OIDC account-access description. The implementation node auth-build is complete; cross-browser/device acceptance and executable Gherkin coverage remain tracked separately.

Requirement Implementation and evidence
Invitation-only registration AdmissionService creates hashed seven-day invitations. EmailAccounts checks eligibility before sending and again after email proof under the admission lock. EmailAccountsTest covers concurrent recipients, consumed/revoked/expired invitations and unknown addresses; AdmissionServiceTest verifies expiry and admin-only management.
Returning login without a provider LoginController provides email request, code and fragment-link endpoints. EmailLoginHttpTest verifies actual security-chain admission, a different browser session entering the code, a protected Flow response and shared single-use alternatives.
Greylisting tolerance EmailProofLifetime grants two hours from issuance. EmailLoginChallengesTest verifies 90-minute delay, expiry, replacement, five failed attempts and concurrent code/link redemption.
Controlled mail submission SendmailLoginMail invokes local sendmail with the agreed sender. Five LoginMailTest cases cover message construction, process arguments, rejection and timeout. The operator confirmed the real test email and subsequently confirmed successful initial account setup. No further external mail was sent for this audit.
Request limits and generic responses EmailRequestLimitsTest verifies persistent per-address, per-client and global limits, boundary expiry and concurrent enforcement. LoginController uses the server-resolved client address, returns the same public request result and does not log codes or recipients.
Bootstrap and recovery Initial setup creates the administrator only after email proof. The consumed bootstrap cannot reactivate after deletion. The explicit offline recovery command stores a separate one-time digest and needs email proof. Ten EmailAccountsTest cases include recovery replacement, expiry and data-preserving promotion of an existing account. See admin-recovery.md.
Private identity and current permissions DeviceAuthenticationFilter replaces the security context on every request; AuthenticatedCurrentUser requires an active UUID account. OwnerTransactions supplies the authenticated owner to tracking services. Existing catalog, work, habit and export tests exercise foreign-owner rejection. Admin status does not bypass owner-scoped tracking access.
Administration and blocking AdmissionService exposes account/invitation metadata and version-checked account status changes. Blocking deletes device credentials. AdmissionServiceTest verifies permissions and that reactivation cannot revive revoked credentials. DeviceLoginServiceTest verifies current roles and inactive accounts.
Session lifetime and logout Device credentials expire after 30 days without explicit activity. Passive requests do not renew them. Six DeviceLoginServiceTest and seven AuthenticatedHttpTest cases cover revocation, ambiguous cookies, CSRF, activity and logout-all owner isolation. Frontend checks cover draft cleanup and activity reporting.
Guest entry The login page exposes shared guest access, using the existing guest UUID without administrator rights; covered by EmailLoginHttpTest.
Deletion Dedicated email proof, device-bound short final grant and separate explicit confirmation precede transactional deletion. Seven proof, five transaction and three HTTP tests cover expiry, isolation, rollback and reuse. See account-deletion.md.
Removed provider integration Active security configuration has no OAuth/OIDC registration or callbacks. Inspection of the built JAR found no OAuth2/Nimbus libraries. Historical database changesets remain intact; the old identity table is not used for login.

All 57 tests in the twelve authentication-related test classes listed above passed without failures or skips. The full local run passed 131 JVM tests, 26 operations tests, 17 frontend tests and production smoke including the packaged offline recovery entry point. One separately invoked browser harness is intentionally outside that regular run.

This audit does not claim Cucumber execution, Firefox/Android acceptance, a real deletion email delivery or a production administrator recovery. The original browser evidence partly predates removal of OIDC and must not be treated as end-to-end proof of the new email flow. These acceptance boundaries remain visible in auth-spike, browser-accept and identity-tests.