mirror of
https://github.com/bitwarden/browser
synced 2026-02-26 01:23:24 +00:00
[PM-30785|BEEEP] Remove deprecated master key login with device flow (#17943)
* Remove deprecated master key login with device flow * Resolve conflicts / cleanup * Linting * Fix lint * Run prettier
This commit is contained in:
@@ -13,16 +13,9 @@
|
||||
|
||||
## Standard Auth Request Flows
|
||||
|
||||
### Flow 1: Unauthed user requests approval from device; Approving device has a masterKey in memory
|
||||
### Flow 1: This flow was removed
|
||||
|
||||
1. Unauthed user clicks "Login with device"
|
||||
2. Navigates to `/login-with-device` which creates a `StandardAuthRequest`
|
||||
3. Receives approval from a device with authRequestPublicKey(masterKey)
|
||||
4. Decrypts masterKey
|
||||
5. Decrypts userKey
|
||||
6. Proceeds to vault
|
||||
|
||||
### Flow 2: Unauthed user requests approval from device; Approving device does NOT have a masterKey in memory
|
||||
### Flow 2: Unauthed user requests approval from device; Approving device does NOT need to have a masterKey in memory
|
||||
|
||||
1. Unauthed user clicks "Login with device"
|
||||
2. Navigates to `/login-with-device` which creates a `StandardAuthRequest`
|
||||
@@ -33,28 +26,18 @@
|
||||
**Note:** This flow is an uncommon scenario and relates to TDE off-boarding. The following describes how a user could
|
||||
get into this flow:
|
||||
|
||||
1. An SSO TD user logs into a device via an Admin auth request approval, therefore this device does NOT have a masterKey
|
||||
1. An SSO TD user logs into a device via an Admin auth request approval, therefore this device does NOT need to have a masterKey
|
||||
in memory
|
||||
2. The org admin:
|
||||
- Changes the member decryption options from "Trusted devices" to "Master password" AND
|
||||
- Turns off the "Require single sign-on authentication" policy
|
||||
3. On another device, the user clicks "Login with device", which they can do because the org no longer requires SSO
|
||||
4. The user approves from the device they had previously logged into with SSO TD, which does NOT have a masterKey in
|
||||
4. The user approves from the device they had previously logged into with SSO TD, which does NOT need to have a masterKey in
|
||||
memory
|
||||
|
||||
### Flow 3: Authed SSO TD user requests approval from device; Approving device has a masterKey in memory
|
||||
### Flow 3: This flow was removed
|
||||
|
||||
1. SSO TD user authenticates via SSO
|
||||
2. Navigates to `/login-initiated`
|
||||
3. Clicks "Approve from your other device"
|
||||
4. Navigates to `/login-with-device` which creates a `StandardAuthRequest`
|
||||
5. Receives approval from device with authRequestPublicKey(masterKey)
|
||||
6. Decrypts masterKey
|
||||
7. Decrypts userKey
|
||||
8. Establishes trust (if required)
|
||||
9. Proceeds to vault
|
||||
|
||||
### Flow 4: Authed SSO TD user requests approval from device; Approving device does NOT have a masterKey in memory
|
||||
### Flow 4: Authed SSO TD user requests approval from device; Approving device does NOT need to have a masterKey in memory
|
||||
|
||||
1. SSO TD user authenticates via SSO
|
||||
2. Navigates to `/login-initiated`
|
||||
@@ -89,9 +72,7 @@ userKey. This is how admins are able to send over the authRequestPublicKey(userK
|
||||
|
||||
| Flow | Auth Status | Clicks Button [active route] | Navigates to | Approving device has masterKey in memory\* |
|
||||
| --------------- | ----------- | ----------------------------------------------------- | --------------------------- | ------------------------------------------------- |
|
||||
| Standard Flow 1 | unauthed | "Login with device" [`/login`] | `/login-with-device` | yes |
|
||||
| Standard Flow 2 | unauthed | "Login with device" [`/login`] | `/login-with-device` | no |
|
||||
| Standard Flow 3 | authed | "Approve from your other device" [`/login-initiated`] | `/login-with-device` | yes |
|
||||
| Standard Flow 4 | authed | "Approve from your other device" [`/login-initiated`] | `/login-with-device` | no |
|
||||
| Admin Flow | authed | "Request admin approval"<br>[`/login-initiated`] | `/admin-approval-requested` | NA - admin requests always send encrypted userKey |
|
||||
|
||||
|
||||
@@ -605,10 +605,10 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy {
|
||||
if (authRequestResponse.requestApproved) {
|
||||
const userHasAuthenticatedViaSSO = this.authStatus === AuthenticationStatus.Locked;
|
||||
if (userHasAuthenticatedViaSSO) {
|
||||
// [Standard Flow 3-4] Handle authenticated SSO TD user flows
|
||||
// [Standard Flow 4] Handle authenticated SSO TD user flows
|
||||
return await this.handleAuthenticatedFlows(authRequestResponse);
|
||||
} else {
|
||||
// [Standard Flow 1-2] Handle unauthenticated user flows
|
||||
// [Standard Flow 2] Handle unauthenticated user flows
|
||||
return await this.handleUnauthenticatedFlows(authRequestResponse, requestId);
|
||||
}
|
||||
}
|
||||
@@ -629,7 +629,7 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async handleAuthenticatedFlows(authRequestResponse: AuthRequestResponse) {
|
||||
// [Standard Flow 3-4] Handle authenticated SSO TD user flows
|
||||
// [Standard Flow 4] Handle authenticated SSO TD user flows
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
if (!userId) {
|
||||
this.logService.error(
|
||||
@@ -654,7 +654,7 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy {
|
||||
authRequestResponse: AuthRequestResponse,
|
||||
requestId: string,
|
||||
) {
|
||||
// [Standard Flow 1-2] Handle unauthenticated user flows
|
||||
// [Standard Flow 2] Handle unauthenticated user flows
|
||||
const authRequestLoginCredentials = await this.buildAuthRequestLoginCredentials(
|
||||
requestId,
|
||||
authRequestResponse,
|
||||
@@ -679,27 +679,12 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy {
|
||||
privateKey: Uint8Array,
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
/**
|
||||
* [Flow Type Detection]
|
||||
* We determine the type of `key` based on the presence or absence of `masterPasswordHash`:
|
||||
* - If `masterPasswordHash` exists: Standard Flow 1 or 3 (device has masterKey)
|
||||
* - If no `masterPasswordHash`: Standard Flow 2, 4, or Admin Flow (device sends userKey)
|
||||
*/
|
||||
if (authRequestResponse.masterPasswordHash) {
|
||||
// [Standard Flow 1 or 3] Device has masterKey
|
||||
await this.authRequestService.setKeysAfterDecryptingSharedMasterKeyAndHash(
|
||||
authRequestResponse,
|
||||
privateKey,
|
||||
userId,
|
||||
);
|
||||
} else {
|
||||
// [Standard Flow 2, 4, or Admin Flow] Device sends userKey
|
||||
await this.authRequestService.setUserKeyAfterDecryptingSharedUserKey(
|
||||
authRequestResponse,
|
||||
privateKey,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
// [Standard Flow 2, 4, or Admin Flow] Device sends userKey
|
||||
await this.authRequestService.setUserKeyAfterDecryptingSharedUserKey(
|
||||
authRequestResponse,
|
||||
privateKey,
|
||||
userId,
|
||||
);
|
||||
|
||||
// [Admin Flow Cleanup] Clear one-time use admin auth request
|
||||
// clear the admin auth request from state so it cannot be used again (it's a one time use)
|
||||
@@ -758,43 +743,13 @@ export class LoginViaAuthRequestComponent implements OnInit, OnDestroy {
|
||||
|
||||
/**
|
||||
* See verifyAndHandleApprovedAuthReq() for flow details.
|
||||
*
|
||||
* We determine the type of `key` based on the presence or absence of `masterPasswordHash`:
|
||||
* - If `masterPasswordHash` has a value, we receive the `key` as an authRequestPublicKey(masterKey) [plus we have authRequestPublicKey(masterPasswordHash)]
|
||||
* - If `masterPasswordHash` does not have a value, we receive the `key` as an authRequestPublicKey(userKey)
|
||||
*/
|
||||
if (authRequestResponse.masterPasswordHash) {
|
||||
// ...in Standard Auth Request Flow 1
|
||||
const { masterKey, masterKeyHash } =
|
||||
await this.authRequestService.decryptPubKeyEncryptedMasterKeyAndHash(
|
||||
authRequestResponse.key,
|
||||
authRequestResponse.masterPasswordHash,
|
||||
this.authRequestKeyPair.privateKey,
|
||||
);
|
||||
|
||||
return new AuthRequestLoginCredentials(
|
||||
this.email,
|
||||
this.accessCode,
|
||||
requestId,
|
||||
null, // no userKey
|
||||
masterKey,
|
||||
masterKeyHash,
|
||||
);
|
||||
} else {
|
||||
// ...in Standard Auth Request Flow 2
|
||||
const userKey = await this.authRequestService.decryptPubKeyEncryptedUserKey(
|
||||
authRequestResponse.key,
|
||||
this.authRequestKeyPair.privateKey,
|
||||
);
|
||||
return new AuthRequestLoginCredentials(
|
||||
this.email,
|
||||
this.accessCode,
|
||||
requestId,
|
||||
userKey,
|
||||
null, // no masterKey
|
||||
null, // no masterKeyHash
|
||||
);
|
||||
}
|
||||
// ...in Standard Auth Request Flow 2
|
||||
const userKey = await this.authRequestService.decryptPubKeyEncryptedUserKey(
|
||||
authRequestResponse.key,
|
||||
this.authRequestKeyPair.privateKey,
|
||||
);
|
||||
return new AuthRequestLoginCredentials(this.email, this.accessCode, requestId, userKey);
|
||||
}
|
||||
|
||||
private async clearExistingAdminAuthRequestAndStartNewRequest(userId: UserId) {
|
||||
|
||||
Reference in New Issue
Block a user