mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-19 01:51:27 +01:00
PM-8113 - Webauthn 2FA - As webauthn popout doesn't persist SSO state, have to genercize success logic (which should be a good thing but requires confirmation testing).
This commit is contained in:
parent
2b9f97a7b6
commit
5b6f5520d1
@ -5,7 +5,12 @@ import {
|
|||||||
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||||
|
|
||||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||||
import { closeSsoAuthResultPopout } from "../popup/utils/auth-popout-window";
|
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
|
||||||
|
import {
|
||||||
|
AuthPopoutType,
|
||||||
|
closeSsoAuthResultPopout,
|
||||||
|
closeTwoFactorAuthPopout,
|
||||||
|
} from "../popup/utils/auth-popout-window";
|
||||||
|
|
||||||
export class ExtensionTwoFactorAuthComponentService
|
export class ExtensionTwoFactorAuthComponentService
|
||||||
extends DefaultTwoFactorAuthComponentService
|
extends DefaultTwoFactorAuthComponentService
|
||||||
@ -36,17 +41,40 @@ export class ExtensionTwoFactorAuthComponentService
|
|||||||
this.window.close();
|
this.window.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleSso2faFlowSuccess(): Promise<void> {
|
async handle2faSuccess(): Promise<void> {
|
||||||
|
// TODO: confirm that moving this from SSO flow only to general flow doesn't introduce any issues
|
||||||
// Force sidebars (FF && Opera) to reload while exempting current window
|
// Force sidebars (FF && Opera) to reload while exempting current window
|
||||||
// because we are just going to close the current window.
|
// because we are just going to close the current window if it is in a popout
|
||||||
|
// or navigate forward if it is in the popup
|
||||||
BrowserApi.reloadOpenWindows(true);
|
BrowserApi.reloadOpenWindows(true);
|
||||||
|
|
||||||
// We don't need this window anymore because the intent is for the user to be left
|
await this.closeSingleActionPopouts();
|
||||||
// on the web vault screen which tells them to continue in the browser extension (sidebar or popup)
|
}
|
||||||
// We don't want the user to be left with a floating, popped out extension which could be lost behind
|
|
||||||
// another window or minimized. Currently, the popped out window thinks it is active and wouldn't time out
|
private async closeSingleActionPopouts(): Promise<void> {
|
||||||
// which leads to the security concern. So, we close the popped out extension to avoid this.
|
// If we are in a single action popout, we don't need the popout anymore because the intent
|
||||||
await closeSsoAuthResultPopout();
|
// is for the user to be left on the web vault screen which tells them to continue in
|
||||||
|
// the browser extension (sidebar or popup). We don't want the user to be left with a
|
||||||
|
// floating, popped out extension which could be lost behind another window or minimized.
|
||||||
|
// Currently, the popped out window thinks it is active and wouldn't time out which
|
||||||
|
// leads to the security concern. So, we close the popped out extension to avoid this.
|
||||||
|
const inSsoAuthResultPopout = BrowserPopupUtils.inSingleActionPopout(
|
||||||
|
this.window,
|
||||||
|
AuthPopoutType.ssoAuthResult,
|
||||||
|
);
|
||||||
|
if (inSsoAuthResultPopout) {
|
||||||
|
await closeSsoAuthResultPopout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inTwoFactorAuthPopout = BrowserPopupUtils.inSingleActionPopout(
|
||||||
|
this.window,
|
||||||
|
AuthPopoutType.twoFactorAuth,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (inTwoFactorAuthPopout) {
|
||||||
|
await closeTwoFactorAuthPopout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async isLinux(): Promise<boolean> {
|
private async isLinux(): Promise<boolean> {
|
||||||
|
@ -72,7 +72,10 @@ export class TwoFactorAuthWebAuthnComponent implements OnInit, OnDestroy {
|
|||||||
const webAuthnResponse = this.route.snapshot.paramMap.get("webAuthnResponse");
|
const webAuthnResponse = this.route.snapshot.paramMap.get("webAuthnResponse");
|
||||||
|
|
||||||
if (webAuthnResponse != null) {
|
if (webAuthnResponse != null) {
|
||||||
|
// TODO: determine if we even need this with the top level processing of the webauthn response.
|
||||||
this.token.emit(webAuthnResponse);
|
this.token.emit(webAuthnResponse);
|
||||||
|
// TODO: should we early return?
|
||||||
|
// return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +47,8 @@ export abstract class TwoFactorAuthComponentService {
|
|||||||
abstract determineLegacyKeyMigrationAction(): LegacyKeyMigrationAction;
|
abstract determineLegacyKeyMigrationAction(): LegacyKeyMigrationAction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally handles the success flow for the SSO + 2FA required flow.
|
* Optionally executes 2FA success logic.
|
||||||
* Only defined on clients that require custom success handling.
|
* Only defined on clients that require custom success handling.
|
||||||
*/
|
*/
|
||||||
abstract handleSso2faFlowSuccess?(): Promise<void>;
|
abstract handle2faSuccess?(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -146,6 +146,8 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (this.twoFactorAuthComponentService.shouldCheckForWebauthnResponseOnInit()) {
|
if (this.twoFactorAuthComponentService.shouldCheckForWebauthnResponseOnInit()) {
|
||||||
await this.processWebAuthnResponseIfExists();
|
await this.processWebAuthnResponseIfExists();
|
||||||
|
// TODO: should we return here?
|
||||||
|
// return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.setSelected2faProviderType();
|
await this.setSelected2faProviderType();
|
||||||
@ -336,12 +338,9 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
|||||||
return await this.handleChangePasswordRequired(this.orgSsoIdentifier);
|
return await this.handleChangePasswordRequired(this.orgSsoIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we are in the SSO flow and we have a custom success handler, call it
|
// if we have a custom success handler, call it
|
||||||
if (
|
if (this.twoFactorAuthComponentService.handle2faSuccess !== undefined) {
|
||||||
this.inSsoFlow &&
|
await this.twoFactorAuthComponentService.handle2faSuccess();
|
||||||
this.twoFactorAuthComponentService.handleSso2faFlowSuccess !== undefined
|
|
||||||
) {
|
|
||||||
await this.twoFactorAuthComponentService.handleSso2faFlowSuccess();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,8 +394,8 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.twoFactorAuthComponentService.handleSso2faFlowSuccess !== undefined) {
|
if (this.twoFactorAuthComponentService.handle2faSuccess !== undefined) {
|
||||||
await this.twoFactorAuthComponentService.handleSso2faFlowSuccess();
|
await this.twoFactorAuthComponentService.handle2faSuccess();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user