Admin Portal - Fix GetTwoFactorProviders wrong exception type handling on Organization and User - #8234
Conversation
GetTwoFactorProviders catches JsonException intending to return null when TwoFactorProviders contains invalid JSON (as its doc comment promises). Organization.cs imports System.Text.Json, so that catch binds to System.Text.Json.JsonException — but JsonHelpers.LegacyDeserialize uses Newtonsoft.Json under the hood and throws Newtonsoft.Json.JsonException (or its JsonReaderException / JsonSerializationException subclasses), which is an unrelated type. The catch never matched and the exception bubbled up through the admin console Organizations view any time a row had a malformed TwoFactorProviders value, taking down the whole page. Trigger observed locally: integration-test orgs seeded via AutoFixture had "TwoFactorProviders" + Guid.NewGuid() left in the column (the default AutoFixture string generator uses the property name as a prefix), which is not valid JSON. Fix: catch Newtonsoft.Json.JsonException (base of both reader and serialization exceptions) so the method degrades to null as intended. Drop the now-unused System.Text.Json using. Add a theory covering pure garbage, the AutoFixture pattern, malformed JSON, and a schema mismatch.
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE The core fix is correct: Code Review Details
Previously raised and closed by the author: the login-path fail-open on |
User.cs has the identical defect Organization.cs did: it imports System.Text.Json, so its catch (JsonException) binds to System.Text.Json.JsonException — but JsonHelpers.LegacyDeserialize uses Newtonsoft.Json and throws Newtonsoft.Json.JsonException. The catch never matched, so a User row with malformed TwoFactorProviders would bubble up through any caller (e.g. TwoFactorIsEnabledQuery, fanned out by Admin/Controllers/UsersController), taking down the admin console Users view the same way orgs did. Fix mirrors the Organization commit: catch Newtonsoft.Json.JsonException, drop the now-unused System.Text.Json using, add the same four-case invalid-JSON theory to UserTests.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #8234 +/- ##
==========================================
+ Coverage 63.29% 68.56% +5.27%
==========================================
Files 2383 2399 +16
Lines 103921 103955 +34
Branches 9403 9409 +6
==========================================
+ Hits 65778 71280 +5502
+ Misses 35899 30325 -5574
- Partials 2244 2350 +106 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Now that Newtonsoft parse failures degrade to null instead of bubbling up as a 500, corruption of the TwoFactorProviders column is silent on the login and admin Users paths. Warn-level log inside TwoFactorIsEnabledQuery.GetEnabledTwoFactorProviders records the user id (never the raw column, which carries 2FA secrets and metadata) when providers is null but the column is non-empty — distinguishing a parse failure from a normal "no 2FA configured" user.
🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-42460
📔 Objective
Organization.GetTwoFactorProvidersandUser.GetTwoFactorProvidersboth catchJsonExceptionintending to returnnullon malformed JSON (per their doc comments). ButOrganization.csandUser.cseach importSystem.Text.Json, so the catch binds toSystem.Text.Json.JsonException— whileJsonHelpers.LegacyDeserializeuses Newtonsoft under the hood and throwsNewtonsoft.Json.JsonException(or itsJsonReaderException/JsonSerializationExceptionsubclasses), an unrelated type. The catch never matched, so any row with an invalidTwoFactorProvidersvalue took down the admin console Organizations view (viaAdmin/Controllers/OrganizationsController) and would take down the Users view the same way (viaTwoFactorIsEnabledQueryfanned out byAdmin/Controllers/UsersController).Observed locally: integration-test rows seeded via AutoFixture left
"TwoFactorProviders" + Guid.NewGuid()in the column (AutoFixture's default string generator prefixes with the property name), which is not valid JSON.Fix: catch
Newtonsoft.Json.JsonException(base of both reader and serialization exceptions) on both entities so the methods degrade tonullas intended, drop the now-unusedSystem.Text.Jsonusing, and add matching theories onOrganizationTestsandUserTestscovering pure garbage, the AutoFixture pattern, malformed JSON, and a schema mismatch.📸 Screenshots
Before:
After: