mirror of
https://github.com/bitwarden/browser
synced 2025-12-11 22:03:36 +00:00
[PM-5499] auth request service migrations (#8597)
* move auth request storage to service * create migrations for auth requests * fix tests * fix browser * fix login strategy * update migration * use correct test descriptions in migration
This commit is contained in:
@@ -33,6 +33,7 @@ import { StateService } from "@bitwarden/common/platform/abstractions/state.serv
|
||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { CaptchaProtectedComponent } from "./captcha-protected.component";
|
||||
|
||||
@@ -131,6 +132,7 @@ export class LoginViaAuthRequestComponent
|
||||
// This also prevents it from being lost on refresh as the
|
||||
// login service email does not persist.
|
||||
this.email = await this.stateService.getEmail();
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
||||
|
||||
if (!this.email) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("userEmailMissing"));
|
||||
@@ -142,10 +144,10 @@ export class LoginViaAuthRequestComponent
|
||||
|
||||
// We only allow a single admin approval request to be active at a time
|
||||
// so must check state to see if we have an existing one or not
|
||||
const adminAuthReqStorable = await this.stateService.getAdminAuthRequest();
|
||||
const adminAuthReqStorable = await this.authRequestService.getAdminAuthRequest(userId);
|
||||
|
||||
if (adminAuthReqStorable) {
|
||||
await this.handleExistingAdminAuthRequest(adminAuthReqStorable);
|
||||
await this.handleExistingAdminAuthRequest(adminAuthReqStorable, userId);
|
||||
} else {
|
||||
// No existing admin auth request; so we need to create one
|
||||
await this.startAuthRequestLogin();
|
||||
@@ -173,7 +175,10 @@ export class LoginViaAuthRequestComponent
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
private async handleExistingAdminAuthRequest(adminAuthReqStorable: AdminAuthRequestStorable) {
|
||||
private async handleExistingAdminAuthRequest(
|
||||
adminAuthReqStorable: AdminAuthRequestStorable,
|
||||
userId: UserId,
|
||||
) {
|
||||
// Note: on login, the SSOLoginStrategy will also call to see an existing admin auth req
|
||||
// has been approved and handle it if so.
|
||||
|
||||
@@ -183,13 +188,13 @@ export class LoginViaAuthRequestComponent
|
||||
adminAuthReqResponse = await this.apiService.getAuthRequest(adminAuthReqStorable.id);
|
||||
} catch (error) {
|
||||
if (error instanceof ErrorResponse && error.statusCode === HttpStatusCode.NotFound) {
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied();
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied(userId);
|
||||
}
|
||||
}
|
||||
|
||||
// Request doesn't exist anymore
|
||||
if (!adminAuthReqResponse) {
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied();
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied(userId);
|
||||
}
|
||||
|
||||
// Re-derive the user's fingerprint phrase
|
||||
@@ -203,7 +208,7 @@ export class LoginViaAuthRequestComponent
|
||||
|
||||
// Request denied
|
||||
if (adminAuthReqResponse.isAnswered && !adminAuthReqResponse.requestApproved) {
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied();
|
||||
return await this.handleExistingAdminAuthReqDeletedOrDenied(userId);
|
||||
}
|
||||
|
||||
// Request approved
|
||||
@@ -211,6 +216,7 @@ export class LoginViaAuthRequestComponent
|
||||
return await this.handleApprovedAdminAuthRequest(
|
||||
adminAuthReqResponse,
|
||||
adminAuthReqStorable.privateKey,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -219,9 +225,9 @@ export class LoginViaAuthRequestComponent
|
||||
await this.anonymousHubService.createHubConnection(adminAuthReqStorable.id);
|
||||
}
|
||||
|
||||
private async handleExistingAdminAuthReqDeletedOrDenied() {
|
||||
private async handleExistingAdminAuthReqDeletedOrDenied(userId: UserId) {
|
||||
// clear the admin auth request from state
|
||||
await this.stateService.setAdminAuthRequest(null);
|
||||
await this.authRequestService.clearAdminAuthRequest(userId);
|
||||
|
||||
// start new auth request
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
@@ -269,7 +275,8 @@ export class LoginViaAuthRequestComponent
|
||||
privateKey: this.authRequestKeyPair.privateKey,
|
||||
});
|
||||
|
||||
await this.stateService.setAdminAuthRequest(adminAuthReqStorable);
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
||||
await this.authRequestService.setAdminAuthRequest(adminAuthReqStorable, userId);
|
||||
} else {
|
||||
await this.buildAuthRequest(AuthRequestType.AuthenticateAndUnlock);
|
||||
reqResponse = await this.apiService.postAuthRequest(this.authRequest);
|
||||
@@ -333,9 +340,11 @@ export class LoginViaAuthRequestComponent
|
||||
|
||||
// if user has authenticated via SSO
|
||||
if (this.userAuthNStatus === AuthenticationStatus.Locked) {
|
||||
const userId = (await firstValueFrom(this.accountService.activeAccount$)).id;
|
||||
return await this.handleApprovedAdminAuthRequest(
|
||||
authReqResponse,
|
||||
this.authRequestKeyPair.privateKey,
|
||||
userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -363,6 +372,7 @@ export class LoginViaAuthRequestComponent
|
||||
async handleApprovedAdminAuthRequest(
|
||||
adminAuthReqResponse: AuthRequestResponse,
|
||||
privateKey: ArrayBuffer,
|
||||
userId: UserId,
|
||||
) {
|
||||
// See verifyAndHandleApprovedAuthReq(...) for flow details
|
||||
// it's flow 2 or 3 based on presence of masterPasswordHash
|
||||
@@ -384,7 +394,7 @@ export class LoginViaAuthRequestComponent
|
||||
|
||||
// clear the admin auth request from state so it cannot be used again (it's a one time use)
|
||||
// TODO: this should eventually be enforced via deleting this on the server once it is used
|
||||
await this.stateService.setAdminAuthRequest(null);
|
||||
await this.authRequestService.clearAdminAuthRequest(userId);
|
||||
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("loginApproved"));
|
||||
|
||||
|
||||
@@ -740,6 +740,7 @@ const safeProviders: SafeProvider[] = [
|
||||
LOGOUT_CALLBACK,
|
||||
StateServiceAbstraction,
|
||||
AuthServiceAbstraction,
|
||||
AuthRequestServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
],
|
||||
}),
|
||||
@@ -963,6 +964,7 @@ const safeProviders: SafeProvider[] = [
|
||||
InternalMasterPasswordServiceAbstraction,
|
||||
CryptoServiceAbstraction,
|
||||
ApiServiceAbstraction,
|
||||
StateProvider,
|
||||
],
|
||||
}),
|
||||
safeProvider({
|
||||
|
||||
Reference in New Issue
Block a user