1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-22 16:29:09 +01:00

[SG-698] Passwordless Login with 2FA enabled does not redirect to 2FA page (#3820)

* added 2fa enabled

* added passwordless authentication to 2fa

* passwordless strategy to authservice

* changes to 2FA to allow email sending for passwordless

* updated imports
This commit is contained in:
Gbubemi Smith 2022-10-19 10:21:20 -06:00 committed by GitHub
parent ff3420d373
commit cc0199d351
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 12 deletions

View File

@ -237,6 +237,8 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
request.email = this.authService.email; request.email = this.authService.email;
request.masterPasswordHash = this.authService.masterPasswordHash; request.masterPasswordHash = this.authService.masterPasswordHash;
request.deviceIdentifier = await this.appIdService.getAppId(); request.deviceIdentifier = await this.appIdService.getAppId();
request.authRequestAccessCode = this.authService.accessCode;
request.authRequestId = this.authService.authRequestId;
this.emailPromise = this.apiService.postTwoFactorEmail(request); this.emailPromise = this.apiService.postTwoFactorEmail(request);
await this.emailPromise; await this.emailPromise;
if (doToast) { if (doToast) {
@ -274,7 +276,8 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
return ( return (
this.authService.authingWithPassword() || this.authService.authingWithPassword() ||
this.authService.authingWithSso() || this.authService.authingWithSso() ||
this.authService.authingWithApiKey() this.authService.authingWithApiKey() ||
this.authService.authingWithPasswordless()
); );
} }

View File

@ -15,6 +15,9 @@ import { AuthRequestPushNotification } from "../models/response/notification.res
export abstract class AuthService { export abstract class AuthService {
masterPasswordHash: string; masterPasswordHash: string;
email: string; email: string;
accessCode: string;
authRequestId: string;
logIn: ( logIn: (
credentials: credentials:
| ApiLogInCredentials | ApiLogInCredentials
@ -31,6 +34,7 @@ export abstract class AuthService {
authingWithApiKey: () => boolean; authingWithApiKey: () => boolean;
authingWithSso: () => boolean; authingWithSso: () => boolean;
authingWithPassword: () => boolean; authingWithPassword: () => boolean;
authingWithPasswordless: () => boolean;
getAuthStatus: (userId?: string) => Promise<AuthenticationStatus>; getAuthStatus: (userId?: string) => Promise<AuthenticationStatus>;
authResponsePushNotifiction: (notification: AuthRequestPushNotification) => Promise<any>; authResponsePushNotifiction: (notification: AuthRequestPushNotification) => Promise<any>;

View File

@ -10,7 +10,6 @@ import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service"; import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { AuthResult } from "../../models/domain/auth-result"; import { AuthResult } from "../../models/domain/auth-result";
import { PasswordlessLogInCredentials } from "../../models/domain/log-in-credentials"; import { PasswordlessLogInCredentials } from "../../models/domain/log-in-credentials";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request"; import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request"; import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
@ -21,14 +20,16 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
return this.tokenRequest.email; return this.tokenRequest.email;
} }
get masterPasswordHash() { get accessCode() {
return this.tokenRequest.masterPasswordHash; return this.passwordlessCredentials.accessCode;
}
get authRequestId() {
return this.passwordlessCredentials.authRequestId;
} }
tokenRequest: PasswordTokenRequest; tokenRequest: PasswordTokenRequest;
private passwordlessCredentials: PasswordlessLogInCredentials;
private localHashedPassword: string;
private key: SymmetricCryptoKey;
constructor( constructor(
cryptoService: CryptoService, cryptoService: CryptoService,
@ -56,8 +57,8 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
} }
async onSuccessfulLogin() { async onSuccessfulLogin() {
await this.cryptoService.setKey(this.key); await this.cryptoService.setKey(this.passwordlessCredentials.decKey);
await this.cryptoService.setKeyHash(this.localHashedPassword); await this.cryptoService.setKeyHash(this.passwordlessCredentials.localPasswordHash);
} }
async logInTwoFactor( async logInTwoFactor(
@ -69,8 +70,7 @@ export class PasswordlessLogInStrategy extends LogInStrategy {
} }
async logIn(credentials: PasswordlessLogInCredentials) { async logIn(credentials: PasswordlessLogInCredentials) {
this.localHashedPassword = credentials.localPasswordHash; this.passwordlessCredentials = credentials;
this.key = credentials.decKey;
this.tokenRequest = new PasswordTokenRequest( this.tokenRequest = new PasswordTokenRequest(
credentials.email, credentials.email,

View File

@ -1,4 +1,5 @@
export class SecretVerificationRequest { export class SecretVerificationRequest {
masterPasswordHash: string; masterPasswordHash: string;
otp: string; otp: string;
authRequestAccessCode: string;
} }

View File

@ -3,4 +3,5 @@ import { SecretVerificationRequest } from "./secret-verification.request";
export class TwoFactorEmailRequest extends SecretVerificationRequest { export class TwoFactorEmailRequest extends SecretVerificationRequest {
email: string; email: string;
deviceIdentifier: string; deviceIdentifier: string;
authRequestId: string;
} }

View File

@ -38,7 +38,14 @@ const sessionTimeoutLength = 2 * 60 * 1000; // 2 minutes
export class AuthService implements AuthServiceAbstraction { export class AuthService implements AuthServiceAbstraction {
get email(): string { get email(): string {
return this.logInStrategy instanceof PasswordLogInStrategy ? this.logInStrategy.email : null; if (
this.logInStrategy instanceof PasswordLogInStrategy ||
this.logInStrategy instanceof PasswordlessLogInStrategy
) {
return this.logInStrategy.email;
}
return null;
} }
get masterPasswordHash(): string { get masterPasswordHash(): string {
@ -47,6 +54,18 @@ export class AuthService implements AuthServiceAbstraction {
: null; : null;
} }
get accessCode(): string {
return this.logInStrategy instanceof PasswordlessLogInStrategy
? this.logInStrategy.accessCode
: null;
}
get authRequestId(): string {
return this.logInStrategy instanceof PasswordlessLogInStrategy
? this.logInStrategy.authRequestId
: null;
}
private logInStrategy: private logInStrategy:
| ApiLogInStrategy | ApiLogInStrategy
| PasswordLogInStrategy | PasswordLogInStrategy
@ -196,6 +215,10 @@ export class AuthService implements AuthServiceAbstraction {
return this.logInStrategy instanceof PasswordLogInStrategy; return this.logInStrategy instanceof PasswordLogInStrategy;
} }
authingWithPasswordless(): boolean {
return this.logInStrategy instanceof PasswordlessLogInStrategy;
}
async getAuthStatus(userId?: string): Promise<AuthenticationStatus> { async getAuthStatus(userId?: string): Promise<AuthenticationStatus> {
const isAuthenticated = await this.stateService.getIsAuthenticated({ userId: userId }); const isAuthenticated = await this.stateService.getIsAuthenticated({ userId: userId });
if (!isAuthenticated) { if (!isAuthenticated) {