Skip to content

[PM-46627] fix: Don't force Key Connector users promoted to admin to set a master password - #7594

Merged
david-livefront merged 1 commit into
bitwarden:mainfrom
acul021:fix/key-connector-admin-master-password
Nov 11, 2026
Merged

david-livefront merged 1 commit into
bitwarden:mainfrom
acul021:fix/key-connector-admin-master-password

Conversation

@acul021

@acul021 acul021 commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

🎟️ Tracking

Reported against a Vaultwarden build with Key Connector support.

Nothing in the client logic is Vaultwarden-specific. A Bitwarden server should hit the same path when a Key Connector user is promoted to owner or admin after migration. I have not reproduced it against a Bitwarden server.

📔 Objective

A Key Connector user who is promoted to owner or admin after migrating to Key Connector cannot log in on Android anymore. The web vault and iOS handle the same account fine.

Steps to reproduce

  1. Set up an organization with SSO and Key Connector.
  2. Log in as a regular member. The account is migrated to Key Connector and has no master password.
  3. Promote the member to admin or owner.
  4. Log in again on Android, or let the app sync.

Expected: The vault unlocks through Key Connector, as it does on web and iOS.
Actual: The app goes to the set password screen. The vault is still locked and the user has no master password, so they can't continue.

Cause

Bitwarden requires TDE users with the "manage account recovery" permission (owners, admins, custom roles with that permission) to set a master password. Android applied this rule to Key Connector users as well, in UserStateJsonExtensions.kt:

  • toUserState computed needsMasterPassword = true for a user without a master password when trustedDevice != null || keyConnectorOptions != null and the user had the permission. RootNavViewModel then routes to RootNavState.SetPassword.
  • getForcePasswordResetReason set TDE_USER_WITHOUT_PASSWORD_HAS_PASSWORD_RESET_PERMISSION on sync for any user without a master password who had the permission, without checking for TDE. The stored reason survives later syncs through previousForcePasswordResetReason.

The other clients only apply this rule to TDE:

  • Web, libs/common/src/platform/sync/default-sync.service.ts: checks userDecryptionOptions.trustedDeviceOption !== undefined.
  • Web, libs/auth/src/common/login-strategies/sso-login.strategy.ts: reads trustedDeviceOption?.hasManageResetPasswordPermission.
  • iOS, SyncService.checkTdeUserNeedsToSetPassword: requires trustedDeviceOption != nil.
  • Android's own login path (GetTokenResponseExtensions.toForcePasswordResetReason) already scopes this to trustedDeviceUserDecryptionOptions. Only the sync and user state paths were missing the check.

Changes

  • needsMasterPassword: a TDE user needs a password only with the reset password permission, a Key Connector user never does, and any other user without a password still does.
  • getForcePasswordResetReason: only sets the TDE reason when trustedDeviceUserDecryptionOptions is present.
  • The Key Connector migration exclusion for owners and admins (removePassword, shouldShowRemovePassword) is unchanged. It matches web.

Tests

New cases in UserStateJsonExtensionsTest:

  • Key Connector user with admin role: needsMasterPassword is false.
  • Key Connector user promoted to admin, then sync: no force password reset reason.

Existing TDE tests are unchanged and pass.

📸 Screenshots

No UI changes.

@acul021
acul021 requested review from a team and david-livefront as code owners November 9, 2026 14:11
Copilot AI balanced review requested due to automatic review settings November 9, 2026 14:11
@CLAassistant

CLAassistant commented Nov 9, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@bitwarden-bot

Copy link
Copy Markdown
Collaborator

Thank you for your contribution! We've added this to our internal tracking system for review.
ID: PM-46627
Link: https://bitwarden.atlassian.net/browse/PM-46627

Details on our contribution process can be found here: https://contributing.bitwarden.com/contributing/pull-requests/community-pr-process.

@bitwarden-bot bitwarden-bot changed the title fix: Don't force Key Connector users promoted to admin to set a master password [PM-46627] fix: Don't force Key Connector users promoted to admin to set a master password Nov 9, 2026
@acul021
acul021 force-pushed the fix/key-connector-admin-master-password branch from b28e9f0 to a810bb3 Compare November 10, 2026 15:54
…r password

A Key Connector user who is promoted to owner or admin after migrating
gets stuck on the set password screen. The vault is still locked at
that point and the user has no master password, so there is no way
forward.

The admin rule comes from Trusted Device Encryption. Android applied
it to Key Connector users too, in two places:

- toUserState set needsMasterPassword for Key Connector users with the
  reset password permission.
- getForcePasswordResetReason set the TDE reset reason for any user
  without a master password, without checking for TDE.

Web (default-sync.service.ts, sso-login.strategy.ts) and iOS
(SyncService.checkTdeUserNeedsToSetPassword) only apply this rule when
trustedDeviceOption is present. Android now does the same.
@acul021
acul021 force-pushed the fix/key-connector-admin-master-password branch from a810bb3 to 9d62a6f Compare November 11, 2026 14:57
@codecov

codecov Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.71429% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 86.85%. Comparing base (051b2ac) to head (9d62a6f).
⚠️ Report is 135 commits behind head on main.

Files with missing lines Patch % Lines
...ta/auth/repository/util/UserStateJsonExtensions.kt 85.71% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7594      +/-   ##
==========================================
+ Coverage   85.73%   86.85%   +1.11%     
==========================================
  Files        1056      898     -158     
  Lines       69016    65202    -3814     
  Branches    10279     9378     -901     
==========================================
- Hits        59170    56630    -2540     
+ Misses       6233     5098    -1135     
+ Partials     3613     3474     -139     
Flag Coverage Δ
app-data 18.99% <85.71%> (+0.59%) ⬆️
app-ui-auth-tools 18.76% <0.00%> (-0.17%) ⬇️
app-ui-platform 16.02% <0.00%> (-0.66%) ⬇️
app-ui-vault 27.02% <0.00%> (-0.67%) ⬇️
authenticator 6.06% <0.00%> (+0.07%) ⬆️
lib-core-network-bridge 4.16% <0.00%> (+0.09%) ⬆️
lib-data-ui 1.33% <0.00%> (+0.15%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@david-livefront
david-livefront added this pull request to the merge queue Nov 11, 2026
@david-livefront

Copy link
Copy Markdown
Collaborator

Thanks for your contribution @acul021

Merged via the queue into bitwarden:main with commit 6b14199 Nov 11, 2026
25 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants