1
0
mirror of https://github.com/bitwarden/browser synced 2025-01-27 19:49:42 +01:00

Auth/PM-13659 - 2FA Timeout - Attempted Fix (#12263)

fix(auth): attempt to resolve 2FA session timeout issue
This commit is contained in:
Jared Snider 2024-12-05 20:22:13 -05:00 committed by GitHub
parent d6e1fe70ca
commit 8d68a2dd58
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 31 additions and 8 deletions

View File

@ -17,6 +17,7 @@ import {
PinService, PinService,
PinServiceAbstraction, PinServiceAbstraction,
UserDecryptionOptionsService, UserDecryptionOptionsService,
Executor,
} from "@bitwarden/auth/common"; } from "@bitwarden/auth/common";
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service"; import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service"; import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/common/abstractions/event/event-upload.service";
@ -614,6 +615,11 @@ export class ServiceContainer {
this.configService, this.configService,
); );
// Execute any authn session timeout logic without any wrapping logic.
// An executor is required to ensure the logic is executed in an Angular context when it
// it is available.
const authnSessionTimeoutExecutor: Executor = (fn) => fn();
this.loginStrategyService = new LoginStrategyService( this.loginStrategyService = new LoginStrategyService(
this.accountService, this.accountService,
this.masterPasswordService, this.masterPasswordService,
@ -640,6 +646,7 @@ export class ServiceContainer {
this.vaultTimeoutSettingsService, this.vaultTimeoutSettingsService,
this.kdfConfigService, this.kdfConfigService,
this.taskSchedulerService, this.taskSchedulerService,
authnSessionTimeoutExecutor,
); );
// FIXME: CLI does not support autofill // FIXME: CLI does not support autofill

View File

@ -1,7 +1,7 @@
import { InjectionToken } from "@angular/core"; import { InjectionToken } from "@angular/core";
import { Observable, Subject } from "rxjs"; import { Observable, Subject } from "rxjs";
import { LogoutReason } from "@bitwarden/auth/common"; import { Executor, LogoutReason } from "@bitwarden/auth/common";
import { ClientType } from "@bitwarden/common/enums"; import { ClientType } from "@bitwarden/common/enums";
import { RegionConfig } from "@bitwarden/common/platform/abstractions/environment.service"; import { RegionConfig } from "@bitwarden/common/platform/abstractions/environment.service";
import { import {
@ -68,3 +68,7 @@ export const REFRESH_ACCESS_TOKEN_ERROR_CALLBACK = new SafeInjectionToken<() =>
export const ENV_ADDITIONAL_REGIONS = new SafeInjectionToken<RegionConfig[]>( export const ENV_ADDITIONAL_REGIONS = new SafeInjectionToken<RegionConfig[]>(
"ENV_ADDITIONAL_REGIONS", "ENV_ADDITIONAL_REGIONS",
); );
export const AUTHN_SESSION_TIMEOUT_EXECUTOR = new SafeInjectionToken<Executor>(
"AuthnSessionTimeoutExecutor",
);

View File

@ -1,4 +1,4 @@
import { ErrorHandler, LOCALE_ID, NgModule } from "@angular/core"; import { ErrorHandler, LOCALE_ID, NgModule, NgZone } from "@angular/core";
import { Subject } from "rxjs"; import { Subject } from "rxjs";
import { import {
@ -319,6 +319,7 @@ import {
CLIENT_TYPE, CLIENT_TYPE,
REFRESH_ACCESS_TOKEN_ERROR_CALLBACK, REFRESH_ACCESS_TOKEN_ERROR_CALLBACK,
ENV_ADDITIONAL_REGIONS, ENV_ADDITIONAL_REGIONS,
AUTHN_SESSION_TIMEOUT_EXECUTOR,
} from "./injection-tokens"; } from "./injection-tokens";
import { ModalService } from "./modal.service"; import { ModalService } from "./modal.service";
@ -411,6 +412,11 @@ const safeProviders: SafeProvider[] = [
TokenServiceAbstraction, TokenServiceAbstraction,
], ],
}), }),
safeProvider({
provide: AUTHN_SESSION_TIMEOUT_EXECUTOR,
useFactory: (ngZone: NgZone) => (fn: () => void) => ngZone.run(fn),
deps: [NgZone],
}),
safeProvider({ safeProvider({
provide: LoginStrategyServiceAbstraction, provide: LoginStrategyServiceAbstraction,
useClass: LoginStrategyService, useClass: LoginStrategyService,
@ -440,6 +446,7 @@ const safeProviders: SafeProvider[] = [
VaultTimeoutSettingsServiceAbstraction, VaultTimeoutSettingsServiceAbstraction,
KdfConfigService, KdfConfigService,
TaskSchedulerService, TaskSchedulerService,
AUTHN_SESSION_TIMEOUT_EXECUTOR,
], ],
}), }),
safeProvider({ safeProvider({

View File

@ -71,6 +71,8 @@ import {
const sessionTimeoutLength = 5 * 60 * 1000; // 5 minutes const sessionTimeoutLength = 5 * 60 * 1000; // 5 minutes
export type Executor = (fn: () => void) => void;
export class LoginStrategyService implements LoginStrategyServiceAbstraction { export class LoginStrategyService implements LoginStrategyServiceAbstraction {
private sessionTimeoutSubscription: Subscription; private sessionTimeoutSubscription: Subscription;
private currentAuthnTypeState: GlobalState<AuthenticationType | null>; private currentAuthnTypeState: GlobalState<AuthenticationType | null>;
@ -118,6 +120,7 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
protected vaultTimeoutSettingsService: VaultTimeoutSettingsService, protected vaultTimeoutSettingsService: VaultTimeoutSettingsService,
protected kdfConfigService: KdfConfigService, protected kdfConfigService: KdfConfigService,
protected taskSchedulerService: TaskSchedulerService, protected taskSchedulerService: TaskSchedulerService,
private authnSessionTimeoutExecutor: Executor = (fn) => fn(), // Default to no-op
) { ) {
this.currentAuthnTypeState = this.stateProvider.get(CURRENT_LOGIN_STRATEGY_KEY); this.currentAuthnTypeState = this.stateProvider.get(CURRENT_LOGIN_STRATEGY_KEY);
this.loginStrategyCacheState = this.stateProvider.get(CACHE_KEY); this.loginStrategyCacheState = this.stateProvider.get(CACHE_KEY);
@ -128,12 +131,14 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction {
this.taskSchedulerService.registerTaskHandler( this.taskSchedulerService.registerTaskHandler(
ScheduledTaskNames.loginStrategySessionTimeout, ScheduledTaskNames.loginStrategySessionTimeout,
async () => { async () => {
this.twoFactorTimeoutSubject.next(true); this.authnSessionTimeoutExecutor(async () => {
try { this.twoFactorTimeoutSubject.next(true);
await this.clearCache(); try {
} catch (e) { await this.clearCache();
this.logService.error("Failed to clear cache during session timeout", e); } catch (e) {
} this.logService.error("Failed to clear cache during session timeout", e);
}
});
}, },
); );