diff --git a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts index 31d338fecc7..d0a4d2db1b5 100644 --- a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts +++ b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts @@ -2,90 +2,34 @@ import { AuthService as AbstractAuthService } from "@bitwarden/common/auth/abstr import { AuthService } from "@bitwarden/common/auth/services/auth.service"; import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - apiServiceFactory, ApiServiceInitOptions, + apiServiceFactory, } from "../../../platform/background/service-factories/api-service.factory"; -import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory"; import { CryptoServiceInitOptions, cryptoServiceFactory, } from "../../../platform/background/service-factories/crypto-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - environmentServiceFactory, - EnvironmentServiceInitOptions, -} from "../../../platform/background/service-factories/environment-service.factory"; import { CachedServices, - factory, FactoryOptions, + factory, } from "../../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../../platform/background/service-factories/log-service.factory"; import { messagingServiceFactory, MessagingServiceInitOptions, } from "../../../platform/background/service-factories/messaging-service.factory"; import { - platformUtilsServiceFactory, - PlatformUtilsServiceInitOptions, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; -import { - stateServiceFactory, StateServiceInitOptions, + stateServiceFactory, } from "../../../platform/background/service-factories/state-service.factory"; -import { - passwordStrengthServiceFactory, - PasswordStrengthServiceInitOptions, -} from "../../../tools/background/service_factories/password-strength-service.factory"; -import { - authRequestCryptoServiceFactory, - AuthRequestCryptoServiceInitOptions, -} from "./auth-request-crypto-service.factory"; -import { - deviceTrustCryptoServiceFactory, - DeviceTrustCryptoServiceInitOptions, -} from "./device-trust-crypto-service.factory"; -import { - keyConnectorServiceFactory, - KeyConnectorServiceInitOptions, -} from "./key-connector-service.factory"; -import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory"; -import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory"; +type AuthServiceFactoryOptions = FactoryOptions; -type AuthServiceFactoyOptions = FactoryOptions; - -export type AuthServiceInitOptions = AuthServiceFactoyOptions & +export type AuthServiceInitOptions = AuthServiceFactoryOptions & + MessagingServiceInitOptions & CryptoServiceInitOptions & ApiServiceInitOptions & - TokenServiceInitOptions & - PlatformUtilsServiceInitOptions & - MessagingServiceInitOptions & - LogServiceInitOptions & - KeyConnectorServiceInitOptions & - EnvironmentServiceInitOptions & - StateServiceInitOptions & - TwoFactorServiceInitOptions & - I18nServiceInitOptions & - EncryptServiceInitOptions & - PolicyServiceInitOptions & - PasswordStrengthServiceInitOptions & - DeviceTrustCryptoServiceInitOptions & - AuthRequestCryptoServiceInitOptions; + StateServiceInitOptions; export function authServiceFactory( cache: { authService?: AbstractAuthService } & CachedServices, @@ -97,23 +41,10 @@ export function authServiceFactory( opts, async () => new AuthService( + await messagingServiceFactory(cache, opts), await cryptoServiceFactory(cache, opts), await apiServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - await appIdServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await messagingServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await keyConnectorServiceFactory(cache, opts), - await environmentServiceFactory(cache, opts), await stateServiceFactory(cache, opts), - await twoFactorServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await passwordStrengthServiceFactory(cache, opts), - await policyServiceFactory(cache, opts), - await deviceTrustCryptoServiceFactory(cache, opts), - await authRequestCryptoServiceFactory(cache, opts), ), ); } diff --git a/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts b/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts new file mode 100644 index 00000000000..39a31ce3d01 --- /dev/null +++ b/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts @@ -0,0 +1,118 @@ +import { LoginStrategyService, LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; + +import { + policyServiceFactory, + PolicyServiceInitOptions, +} from "../../../admin-console/background/service-factories/policy-service.factory"; +import { + apiServiceFactory, + ApiServiceInitOptions, +} from "../../../platform/background/service-factories/api-service.factory"; +import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory"; +import { + CryptoServiceInitOptions, + cryptoServiceFactory, +} from "../../../platform/background/service-factories/crypto-service.factory"; +import { + EncryptServiceInitOptions, + encryptServiceFactory, +} from "../../../platform/background/service-factories/encrypt-service.factory"; +import { + environmentServiceFactory, + EnvironmentServiceInitOptions, +} from "../../../platform/background/service-factories/environment-service.factory"; +import { + CachedServices, + factory, + FactoryOptions, +} from "../../../platform/background/service-factories/factory-options"; +import { + i18nServiceFactory, + I18nServiceInitOptions, +} from "../../../platform/background/service-factories/i18n-service.factory"; +import { + logServiceFactory, + LogServiceInitOptions, +} from "../../../platform/background/service-factories/log-service.factory"; +import { + messagingServiceFactory, + MessagingServiceInitOptions, +} from "../../../platform/background/service-factories/messaging-service.factory"; +import { + platformUtilsServiceFactory, + PlatformUtilsServiceInitOptions, +} from "../../../platform/background/service-factories/platform-utils-service.factory"; +import { + stateServiceFactory, + StateServiceInitOptions, +} from "../../../platform/background/service-factories/state-service.factory"; +import { + passwordStrengthServiceFactory, + PasswordStrengthServiceInitOptions, +} from "../../../tools/background/service_factories/password-strength-service.factory"; + +import { + authRequestCryptoServiceFactory, + AuthRequestCryptoServiceInitOptions, +} from "./auth-request-crypto-service.factory"; +import { + deviceTrustCryptoServiceFactory, + DeviceTrustCryptoServiceInitOptions, +} from "./device-trust-crypto-service.factory"; +import { + keyConnectorServiceFactory, + KeyConnectorServiceInitOptions, +} from "./key-connector-service.factory"; +import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory"; +import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory"; + +type LoginStrategyServiceFactoryOptions = FactoryOptions; + +export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions & + CryptoServiceInitOptions & + ApiServiceInitOptions & + TokenServiceInitOptions & + PlatformUtilsServiceInitOptions & + MessagingServiceInitOptions & + LogServiceInitOptions & + KeyConnectorServiceInitOptions & + EnvironmentServiceInitOptions & + StateServiceInitOptions & + TwoFactorServiceInitOptions & + I18nServiceInitOptions & + EncryptServiceInitOptions & + PolicyServiceInitOptions & + PasswordStrengthServiceInitOptions & + DeviceTrustCryptoServiceInitOptions & + AuthRequestCryptoServiceInitOptions; + +export function loginStrategyServiceFactory( + cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices, + opts: LoginStrategyServiceInitOptions, +): Promise { + return factory( + cache, + "loginStrategyService", + opts, + async () => + new LoginStrategyService( + await cryptoServiceFactory(cache, opts), + await apiServiceFactory(cache, opts), + await tokenServiceFactory(cache, opts), + await appIdServiceFactory(cache, opts), + await platformUtilsServiceFactory(cache, opts), + await messagingServiceFactory(cache, opts), + await logServiceFactory(cache, opts), + await keyConnectorServiceFactory(cache, opts), + await environmentServiceFactory(cache, opts), + await stateServiceFactory(cache, opts), + await twoFactorServiceFactory(cache, opts), + await i18nServiceFactory(cache, opts), + await encryptServiceFactory(cache, opts), + await passwordStrengthServiceFactory(cache, opts), + await policyServiceFactory(cache, opts), + await deviceTrustCryptoServiceFactory(cache, opts), + await authRequestCryptoServiceFactory(cache, opts), + ), + ); +} diff --git a/apps/browser/src/auth/popup/login-via-auth-request.component.ts b/apps/browser/src/auth/popup/login-via-auth-request.component.ts index b5ff436f14a..46511a5c34d 100644 --- a/apps/browser/src/auth/popup/login-via-auth-request.component.ts +++ b/apps/browser/src/auth/popup/login-via-auth-request.component.ts @@ -3,6 +3,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; @@ -48,6 +49,7 @@ export class LoginViaAuthRequestComponent syncService: SyncService, deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, authReqCryptoService: AuthRequestCryptoServiceAbstraction, + loginStrategyService: LoginStrategyServiceAbstraction, private location: Location, ) { super( @@ -68,6 +70,7 @@ export class LoginViaAuthRequestComponent loginService, deviceTrustCryptoService, authReqCryptoService, + loginStrategyService, ); super.onSuccessfulLogin = async () => { await syncService.fullSync(true); diff --git a/apps/browser/src/auth/popup/login.component.ts b/apps/browser/src/auth/popup/login.component.ts index 20540334335..ddf494153a0 100644 --- a/apps/browser/src/auth/popup/login.component.ts +++ b/apps/browser/src/auth/popup/login.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction"; @@ -30,7 +30,7 @@ export class LoginComponent extends BaseLoginComponent { constructor( devicesApiService: DevicesApiServiceAbstraction, appIdService: AppIdService, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, @@ -50,7 +50,7 @@ export class LoginComponent extends BaseLoginComponent { super( devicesApiService, appIdService, - authService, + loginStrategyService, router, platformUtilsService, i18nService, diff --git a/apps/browser/src/auth/popup/register.component.ts b/apps/browser/src/auth/popup/register.component.ts index 4752c885728..f46289f978e 100644 --- a/apps/browser/src/auth/popup/register.component.ts +++ b/apps/browser/src/auth/popup/register.component.ts @@ -4,9 +4,9 @@ import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -27,7 +27,7 @@ export class RegisterComponent extends BaseRegisterComponent { constructor( formValidationErrorService: FormValidationErrorsService, formBuilder: UntypedFormBuilder, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, cryptoService: CryptoService, @@ -43,7 +43,7 @@ export class RegisterComponent extends BaseRegisterComponent { super( formValidationErrorService, formBuilder, - authService, + loginStrategyService, router, i18nService, cryptoService, diff --git a/apps/browser/src/auth/popup/sso.component.ts b/apps/browser/src/auth/popup/sso.component.ts index e7fceab36eb..c8b8f127296 100644 --- a/apps/browser/src/auth/popup/sso.component.ts +++ b/apps/browser/src/auth/popup/sso.component.ts @@ -3,6 +3,7 @@ import { ActivatedRoute, Router } from "@angular/router"; import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component"; import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -24,7 +25,7 @@ import { BrowserApi } from "../../platform/browser/browser-api"; }) export class SsoComponent extends BaseSsoComponent { constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, route: ActivatedRoute, @@ -37,10 +38,11 @@ export class SsoComponent extends BaseSsoComponent { environmentService: EnvironmentService, logService: LogService, configService: ConfigServiceAbstraction, + protected authService: AuthService, @Inject(WINDOW) private win: Window, ) { super( - authService, + loginStrategyService, router, i18nService, route, diff --git a/apps/browser/src/auth/popup/two-factor.component.ts b/apps/browser/src/auth/popup/two-factor.component.ts index 9daccf9f0be..c663834bce2 100644 --- a/apps/browser/src/auth/popup/two-factor.component.ts +++ b/apps/browser/src/auth/popup/two-factor.component.ts @@ -5,8 +5,8 @@ import { filter, first, takeUntil } from "rxjs/operators"; import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component"; import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -39,7 +39,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { inPopout = BrowserPopupUtils.inPopout(window); constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, apiService: ApiService, @@ -60,7 +60,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { private browserMessagingApi: ZonedMessageListenerService, ) { super( - authService, + loginStrategyService, router, i18nService, apiService, diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 4970dedf7a2..0af91ac3499 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -1,4 +1,9 @@ -import { PinCryptoServiceAbstraction, PinCryptoService } from "@bitwarden/auth/common"; +import { + PinCryptoServiceAbstraction, + PinCryptoService, + LoginStrategyServiceAbstraction, + LoginStrategyService, +} from "@bitwarden/auth/common"; import { AvatarUpdateService as AvatarUpdateServiceAbstraction } from "@bitwarden/common/abstractions/account/avatar-update.service"; import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service"; import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; @@ -214,6 +219,7 @@ export default class MainBackground { containerService: ContainerService; auditService: AuditServiceAbstraction; authService: AuthServiceAbstraction; + loginStrategyService: LoginStrategyServiceAbstraction; importApiService: ImportApiServiceAbstraction; importService: ImportServiceAbstraction; exportService: VaultExportServiceAbstraction; @@ -490,6 +496,13 @@ export default class MainBackground { this.authRequestCryptoService = new AuthRequestCryptoServiceImplementation(this.cryptoService); this.authService = new AuthService( + backgroundMessagingService, + this.cryptoService, + this.apiService, + this.stateService, + ); + + this.loginStrategyService = new LoginStrategyService( this.cryptoService, this.apiService, this.tokenService, diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 536c4de4da8..585c928f76f 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -10,6 +10,7 @@ import { OBSERVABLE_MEMORY_STORAGE, } from "@bitwarden/angular/services/injection-tokens"; import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -181,6 +182,10 @@ function getBgService(service: keyof MainBackground) { useFactory: getBgService("authService"), deps: [], }, + { + provide: LoginStrategyServiceAbstraction, + useFactory: getBgService("loginStrategyService"), + }, { provide: SearchServiceAbstraction, useFactory: (logService: ConsoleLogService, i18nService: I18nServiceAbstraction) => { diff --git a/apps/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index 468d03b0e3c..ae0949252a6 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -5,6 +5,12 @@ import * as inquirer from "inquirer"; import Separator from "inquirer/lib/objects/separator"; import { firstValueFrom } from "rxjs"; +import { + LoginStrategyServiceAbstraction, + PasswordLoginCredentials, + SsoLoginCredentials, + UserApiLoginCredentials, +} from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; @@ -15,11 +21,6 @@ import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { - PasswordLoginCredentials, - SsoLoginCredentials, - UserApiLoginCredentials, -} from "@bitwarden/common/auth/models/domain/login-credentials"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request"; import { TwoFactorEmailRequest } from "@bitwarden/common/auth/models/request/two-factor-email.request"; @@ -50,6 +51,7 @@ export class LoginCommand { private options: OptionValues; constructor( + protected loginStrategyService: LoginStrategyServiceAbstraction, protected authService: AuthService, protected apiService: ApiService, protected cryptoFunctionService: CryptoFunctionService, @@ -178,7 +180,7 @@ export class LoginCommand { return Response.error("Invalid API Key; Organization API Key currently not supported"); } try { - response = await this.authService.logIn( + response = await this.loginStrategyService.logIn( new UserApiLoginCredentials(clientId, clientSecret), ); } catch (e) { @@ -195,7 +197,7 @@ export class LoginCommand { throw e; } } else if (ssoCode != null && ssoCodeVerifier != null) { - response = await this.authService.logIn( + response = await this.loginStrategyService.logIn( new SsoLoginCredentials( ssoCode, ssoCodeVerifier, @@ -205,7 +207,7 @@ export class LoginCommand { ), ); } else { - response = await this.authService.logIn( + response = await this.loginStrategyService.logIn( new PasswordLoginCredentials(email, password, null, twoFactor), ); } @@ -271,8 +273,8 @@ export class LoginCommand { selectedProvider.type === TwoFactorProviderType.Email ) { const emailReq = new TwoFactorEmailRequest(); - emailReq.email = this.authService.email; - emailReq.masterPasswordHash = this.authService.masterPasswordHash; + emailReq.email = this.loginStrategyService.email; + emailReq.masterPasswordHash = this.loginStrategyService.masterPasswordHash; await this.apiService.postTwoFactorEmail(emailReq); } @@ -292,7 +294,7 @@ export class LoginCommand { } } - response = await this.authService.logInTwoFactor( + response = await this.loginStrategyService.logInTwoFactor( new TokenTwoFactorRequest(selectedProvider.type, twoFactorToken), null, ); @@ -604,9 +606,9 @@ export class LoginCommand { if (credentials != null) { credentials.captchaToken = captchaClientSecret; credentials.twoFactor = twoFactorRequest; - authResultResponse = await this.authService.logIn(credentials); + authResultResponse = await this.loginStrategyService.logIn(credentials); } else { - authResultResponse = await this.authService.logInTwoFactor( + authResultResponse = await this.loginStrategyService.logInTwoFactor( twoFactorRequest, captchaClientSecret, ); diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index c87d380ec3d..1b0ed038019 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -4,7 +4,12 @@ import * as path from "path"; import { program } from "commander"; import * as jsdom from "jsdom"; -import { PinCryptoServiceAbstraction, PinCryptoService } from "@bitwarden/auth/common"; +import { + LoginStrategyService, + LoginStrategyServiceAbstraction, + PinCryptoService, + PinCryptoServiceAbstraction, +} from "@bitwarden/auth/common"; 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 { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; @@ -191,6 +196,7 @@ export class Main { activeUserStateProvider: ActiveUserStateProvider; derivedStateProvider: DerivedStateProvider; stateProvider: StateProvider; + loginStrategyService: LoginStrategyServiceAbstraction; constructor() { let p = null; @@ -393,7 +399,7 @@ export class Main { this.authRequestCryptoService = new AuthRequestCryptoServiceImplementation(this.cryptoService); - this.authService = new AuthService( + this.loginStrategyService = new LoginStrategyService( this.cryptoService, this.apiService, this.tokenService, @@ -413,6 +419,13 @@ export class Main { this.authRequestCryptoService, ); + this.authService = new AuthService( + this.messagingService, + this.cryptoService, + this.apiService, + this.stateService, + ); + this.configApiService = new ConfigApiService(this.apiService, this.authService); this.configService = new CliConfigService( diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index dec8edd311b..a2c6ea8a8d5 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -139,6 +139,7 @@ export class Program { if (!options.check) { await this.exitIfAuthed(); const command = new LoginCommand( + this.main.loginStrategyService, this.main.authService, this.main.apiService, this.main.cryptoFunctionService, diff --git a/apps/desktop/src/auth/login/login-approval.component.ts b/apps/desktop/src/auth/login/login-approval.component.ts index a870d2add6a..e39e73662e5 100644 --- a/apps/desktop/src/auth/login/login-approval.component.ts +++ b/apps/desktop/src/auth/login/login-approval.component.ts @@ -4,8 +4,8 @@ import { Component, OnInit, OnDestroy, Inject } from "@angular/core"; import { Subject, firstValueFrom } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -50,7 +50,7 @@ export class LoginApprovalComponent implements OnInit, OnDestroy { protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, protected apiService: ApiService, - protected authService: AuthService, + protected loginStrategyService: LoginStrategyServiceAbstraction, protected appIdService: AppIdService, protected cryptoService: CryptoService, private dialogRef: DialogRef, @@ -121,7 +121,7 @@ export class LoginApprovalComponent implements OnInit, OnDestroy { this.i18nService.t("thisRequestIsNoLongerValid"), ); } else { - const loginResponse = await this.authService.passwordlessLogin( + const loginResponse = await this.loginStrategyService.passwordlessLogin( this.authRequestResponse.id, this.authRequestResponse.publicKey, approve, diff --git a/apps/desktop/src/auth/login/login-via-auth-request.component.ts b/apps/desktop/src/auth/login/login-via-auth-request.component.ts index e61c68c5cba..26d6d654966 100644 --- a/apps/desktop/src/auth/login/login-via-auth-request.component.ts +++ b/apps/desktop/src/auth/login/login-via-auth-request.component.ts @@ -4,6 +4,7 @@ import { Router } from "@angular/router"; import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component"; import { ModalService } from "@bitwarden/angular/services/modal.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; @@ -56,6 +57,7 @@ export class LoginViaAuthRequestComponent loginService: LoginService, deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, authReqCryptoService: AuthRequestCryptoServiceAbstraction, + loginStrategyService: LoginStrategyServiceAbstraction, private location: Location, ) { super( @@ -76,6 +78,7 @@ export class LoginViaAuthRequestComponent loginService, deviceTrustCryptoService, authReqCryptoService, + loginStrategyService, ); super.onSuccessfulLogin = () => { diff --git a/apps/desktop/src/auth/login/login.component.ts b/apps/desktop/src/auth/login/login.component.ts index 65b16ad7b74..d511d64ca90 100644 --- a/apps/desktop/src/auth/login/login.component.ts +++ b/apps/desktop/src/auth/login/login.component.ts @@ -7,7 +7,7 @@ import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; import { ModalService } from "@bitwarden/angular/services/modal.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction"; @@ -55,7 +55,7 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy { constructor( devicesApiService: DevicesApiServiceAbstraction, appIdService: AppIdService, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, syncService: SyncService, @@ -78,7 +78,7 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy { super( devicesApiService, appIdService, - authService, + loginStrategyService, router, platformUtilsService, i18nService, diff --git a/apps/desktop/src/auth/register.component.ts b/apps/desktop/src/auth/register.component.ts index 23ada81ccb1..82b815aa186 100644 --- a/apps/desktop/src/auth/register.component.ts +++ b/apps/desktop/src/auth/register.component.ts @@ -4,9 +4,9 @@ import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -27,7 +27,7 @@ export class RegisterComponent extends BaseRegisterComponent implements OnInit, constructor( formValidationErrorService: FormValidationErrorsService, formBuilder: UntypedFormBuilder, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, cryptoService: CryptoService, @@ -45,7 +45,7 @@ export class RegisterComponent extends BaseRegisterComponent implements OnInit, super( formValidationErrorService, formBuilder, - authService, + loginStrategyService, router, i18nService, cryptoService, diff --git a/apps/desktop/src/auth/sso.component.ts b/apps/desktop/src/auth/sso.component.ts index 7332bd34bc2..954206380b8 100644 --- a/apps/desktop/src/auth/sso.component.ts +++ b/apps/desktop/src/auth/sso.component.ts @@ -2,8 +2,8 @@ import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -20,7 +20,7 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv }) export class SsoComponent extends BaseSsoComponent { constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, syncService: SyncService, @@ -35,7 +35,7 @@ export class SsoComponent extends BaseSsoComponent { configService: ConfigServiceAbstraction, ) { super( - authService, + loginStrategyService, router, i18nService, route, diff --git a/apps/desktop/src/auth/two-factor.component.ts b/apps/desktop/src/auth/two-factor.component.ts index 0c522434665..d483c3fd2e5 100644 --- a/apps/desktop/src/auth/two-factor.component.ts +++ b/apps/desktop/src/auth/two-factor.component.ts @@ -4,8 +4,8 @@ import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component"; import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; import { ModalService } from "@bitwarden/angular/services/modal.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -32,7 +32,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { showingModal = false; constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, apiService: ApiService, @@ -50,7 +50,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { @Inject(WINDOW) protected win: Window, ) { super( - authService, + loginStrategyService, router, i18nService, apiService, diff --git a/apps/web/src/app/auth/login/login-via-auth-request.component.ts b/apps/web/src/app/auth/login/login-via-auth-request.component.ts index f864b78c838..f7458940121 100644 --- a/apps/web/src/app/auth/login/login-via-auth-request.component.ts +++ b/apps/web/src/app/auth/login/login-via-auth-request.component.ts @@ -2,6 +2,7 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { Router } from "@angular/router"; import { LoginViaAuthRequestComponent as BaseLoginWithDeviceComponent } from "@bitwarden/angular/auth/components/login-via-auth-request.component"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; @@ -46,6 +47,7 @@ export class LoginViaAuthRequestComponent loginService: LoginService, deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, authReqCryptoService: AuthRequestCryptoServiceAbstraction, + loginStrategyService: LoginStrategyServiceAbstraction, ) { super( router, @@ -65,6 +67,7 @@ export class LoginViaAuthRequestComponent loginService, deviceTrustCryptoService, authReqCryptoService, + loginStrategyService, ); } } diff --git a/apps/web/src/app/auth/login/login.component.ts b/apps/web/src/app/auth/login/login.component.ts index ef48aeff674..0add30141e5 100644 --- a/apps/web/src/app/auth/login/login.component.ts +++ b/apps/web/src/app/auth/login/login.component.ts @@ -6,13 +6,13 @@ import { first } from "rxjs/operators"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyData } from "@bitwarden/common/admin-console/models/data/policy.data"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction"; @@ -45,7 +45,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit { constructor( devicesApiService: DevicesApiServiceAbstraction, appIdService: AppIdService, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, route: ActivatedRoute, @@ -69,7 +69,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit { super( devicesApiService, appIdService, - authService, + loginStrategyService, router, platformUtilsService, i18nService, diff --git a/apps/web/src/app/auth/recover-two-factor.component.ts b/apps/web/src/app/auth/recover-two-factor.component.ts index d727a2ab0e3..145c46c8df5 100644 --- a/apps/web/src/app/auth/recover-two-factor.component.ts +++ b/apps/web/src/app/auth/recover-two-factor.component.ts @@ -1,8 +1,8 @@ import { Component } from "@angular/core"; import { Router } from "@angular/router"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { TwoFactorRecoveryRequest } from "@bitwarden/common/auth/models/request/two-factor-recovery.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -25,7 +25,7 @@ export class RecoverTwoFactorComponent { private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, private cryptoService: CryptoService, - private authService: AuthService, + private loginStrategyService: LoginStrategyServiceAbstraction, private logService: LogService, ) {} @@ -34,7 +34,10 @@ export class RecoverTwoFactorComponent { const request = new TwoFactorRecoveryRequest(); request.recoveryCode = this.recoveryCode.replace(/\s/g, "").toLowerCase(); request.email = this.email.trim().toLowerCase(); - const key = await this.authService.makePreloginKey(this.masterPassword, request.email); + const key = await this.loginStrategyService.makePreloginKey( + this.masterPassword, + request.email, + ); request.masterPasswordHash = await this.cryptoService.hashMasterKey(this.masterPassword, key); this.formPromise = this.apiService.postTwoFactorRecover(request); await this.formPromise; diff --git a/apps/web/src/app/auth/register-form/register-form.component.ts b/apps/web/src/app/auth/register-form/register-form.component.ts index e4254b94ce1..47c6b36f878 100644 --- a/apps/web/src/app/auth/register-form/register-form.component.ts +++ b/apps/web/src/app/auth/register-form/register-form.component.ts @@ -4,11 +4,11 @@ import { Router } from "@angular/router"; import { RegisterComponent as BaseRegisterComponent } from "@bitwarden/angular/auth/components/register.component"; import { FormValidationErrorsService } from "@bitwarden/angular/platform/abstractions/form-validation-errors.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -35,7 +35,7 @@ export class RegisterFormComponent extends BaseRegisterComponent { constructor( formValidationErrorService: FormValidationErrorsService, formBuilder: UntypedFormBuilder, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, cryptoService: CryptoService, @@ -52,7 +52,7 @@ export class RegisterFormComponent extends BaseRegisterComponent { super( formValidationErrorService, formBuilder, - authService, + loginStrategyService, router, i18nService, cryptoService, diff --git a/apps/web/src/app/auth/sso.component.ts b/apps/web/src/app/auth/sso.component.ts index ced14370775..9e60c155ced 100644 --- a/apps/web/src/app/auth/sso.component.ts +++ b/apps/web/src/app/auth/sso.component.ts @@ -3,10 +3,10 @@ import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; import { SsoComponent as BaseSsoComponent } from "@bitwarden/angular/auth/components/sso.component"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction"; import { OrganizationDomainSsoDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain-sso-details.response"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { HttpStatusCode } from "@bitwarden/common/enums"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; @@ -26,7 +26,7 @@ import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/ge // eslint-disable-next-line rxjs-angular/prefer-takeuntil export class SsoComponent extends BaseSsoComponent { constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, route: ActivatedRoute, @@ -42,7 +42,7 @@ export class SsoComponent extends BaseSsoComponent { configService: ConfigServiceAbstraction, ) { super( - authService, + loginStrategyService, router, i18nService, route, diff --git a/apps/web/src/app/auth/two-factor.component.ts b/apps/web/src/app/auth/two-factor.component.ts index 16b8f5b932b..51a29e914f6 100644 --- a/apps/web/src/app/auth/two-factor.component.ts +++ b/apps/web/src/app/auth/two-factor.component.ts @@ -4,8 +4,8 @@ import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component"; import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; import { ModalService } from "@bitwarden/angular/services/modal.service"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -30,7 +30,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest twoFactorOptionsModal: ViewContainerRef; constructor( - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, i18nService: I18nService, apiService: ApiService, @@ -47,7 +47,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent implements OnDest @Inject(WINDOW) protected win: Window, ) { super( - authService, + loginStrategyService, router, i18nService, apiService, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/components/link-sso.directive.ts b/apps/web/src/app/vault/individual-vault/vault-filter/components/link-sso.directive.ts index 180c2ff54c1..ad04161f208 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/components/link-sso.directive.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/components/link-sso.directive.ts @@ -2,9 +2,9 @@ import { AfterContentInit, Directive, HostListener, Input } from "@angular/core" import { ActivatedRoute, Router } from "@angular/router"; import { SsoComponent } from "@bitwarden/angular/auth/components/sso.component"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -31,7 +31,7 @@ export class LinkSsoDirective extends SsoComponent implements AfterContentInit { platformUtilsService: PlatformUtilsService, i18nService: I18nService, apiService: ApiService, - authService: AuthService, + loginStrategyService: LoginStrategyServiceAbstraction, router: Router, route: ActivatedRoute, cryptoFunctionService: CryptoFunctionService, @@ -42,7 +42,7 @@ export class LinkSsoDirective extends SsoComponent implements AfterContentInit { configService: ConfigServiceAbstraction, ) { super( - authService, + loginStrategyService, router, i18nService, route, diff --git a/libs/angular/src/auth/components/login-via-auth-request.component.ts b/libs/angular/src/auth/components/login-via-auth-request.component.ts index c047a3173fd..666a2864573 100644 --- a/libs/angular/src/auth/components/login-via-auth-request.component.ts +++ b/libs/angular/src/auth/components/login-via-auth-request.component.ts @@ -2,6 +2,10 @@ import { Directive, OnDestroy, OnInit } from "@angular/core"; import { IsActiveMatchOptions, Router } from "@angular/router"; import { Subject, takeUntil } from "rxjs"; +import { + AuthRequestLoginCredentials, + LoginStrategyServiceAbstraction, +} from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AnonymousHubService } from "@bitwarden/common/auth/abstractions/anonymous-hub.service"; import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; @@ -13,7 +17,6 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio import { AdminAuthRequestStorable } from "@bitwarden/common/auth/models/domain/admin-auth-req-storable"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { AuthRequestLoginCredentials } from "@bitwarden/common/auth/models/domain/login-credentials"; import { CreateAuthRequest } from "@bitwarden/common/auth/models/request/create-auth.request"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { HttpStatusCode } from "@bitwarden/common/enums/http-status-code.enum"; @@ -84,6 +87,7 @@ export class LoginViaAuthRequestComponent private loginService: LoginService, private deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, private authReqCryptoService: AuthRequestCryptoServiceAbstraction, + private loginStrategyService: LoginStrategyServiceAbstraction, ) { super(environmentService, i18nService, platformUtilsService); @@ -95,7 +99,7 @@ export class LoginViaAuthRequestComponent } //gets signalR push notification - this.authService + this.loginStrategyService .getPushNotificationObs$() .pipe(takeUntil(this.destroy$)) .subscribe((id) => { @@ -438,7 +442,7 @@ export class LoginViaAuthRequestComponent const credentials = await this.buildAuthRequestLoginCredentials(requestId, authReqResponse); // Note: keys are set by AuthRequestLoginStrategy success handling - return await this.authService.logIn(credentials); + return await this.loginStrategyService.logIn(credentials); } // Routing logic diff --git a/libs/angular/src/auth/components/login.component.ts b/libs/angular/src/auth/components/login.component.ts index 5e9d21bee7c..5ef60657b96 100644 --- a/libs/angular/src/auth/components/login.component.ts +++ b/libs/angular/src/auth/components/login.component.ts @@ -4,13 +4,12 @@ import { ActivatedRoute, Router } from "@angular/router"; import { Observable, Subject } from "rxjs"; import { take, takeUntil } from "rxjs/operators"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; +import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common"; import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { WebAuthnLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login.service.abstraction"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { PasswordLoginCredentials } from "@bitwarden/common/auth/models/domain/login-credentials"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; @@ -65,7 +64,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit, constructor( protected devicesApiService: DevicesApiServiceAbstraction, protected appIdService: AppIdService, - protected authService: AuthService, + protected loginStrategyService: LoginStrategyServiceAbstraction, protected router: Router, platformUtilsService: PlatformUtilsService, i18nService: I18nService, @@ -151,7 +150,7 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit, this.captchaToken, null, ); - this.formPromise = this.authService.logIn(credentials); + this.formPromise = this.loginStrategyService.logIn(credentials); const response = await this.formPromise; this.setFormValues(); await this.loginService.saveEmailSettings(); diff --git a/libs/angular/src/auth/components/register.component.ts b/libs/angular/src/auth/components/register.component.ts index 28e64a075b0..3cffebe71be 100644 --- a/libs/angular/src/auth/components/register.component.ts +++ b/libs/angular/src/auth/components/register.component.ts @@ -2,10 +2,9 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { AbstractControl, UntypedFormBuilder, ValidatorFn, Validators } from "@angular/forms"; import { Router } from "@angular/router"; +import { LoginStrategyServiceAbstraction, PasswordLoginCredentials } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { PasswordLoginCredentials } from "@bitwarden/common/auth/models/domain/login-credentials"; import { RegisterResponse } from "@bitwarden/common/auth/models/response/register.response"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; import { ReferenceEventRequest } from "@bitwarden/common/models/request/reference-event.request"; @@ -82,7 +81,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn constructor( protected formValidationErrorService: FormValidationErrorsService, protected formBuilder: UntypedFormBuilder, - protected authService: AuthService, + protected loginStrategyService: LoginStrategyServiceAbstraction, protected router: Router, i18nService: I18nService, protected cryptoService: CryptoService, @@ -333,7 +332,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn captchaBypassToken, null, ); - const loginResponse = await this.authService.logIn(credentials); + const loginResponse = await this.loginStrategyService.logIn(credentials); if (this.handleCaptchaRequired(loginResponse)) { return { captchaRequired: true }; } diff --git a/libs/angular/src/auth/components/sso.component.spec.ts b/libs/angular/src/auth/components/sso.component.spec.ts index 5bdc44d7309..22e47b9996c 100644 --- a/libs/angular/src/auth/components/sso.component.spec.ts +++ b/libs/angular/src/auth/components/sso.component.spec.ts @@ -4,8 +4,8 @@ import { ActivatedRoute, Router } from "@angular/router"; import { MockProxy, mock } from "jest-mock-extended"; import { Observable, of } from "rxjs"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; @@ -46,7 +46,7 @@ describe("SsoComponent", () => { let fixture: ComponentFixture; // Mock Services - let mockAuthService: MockProxy; + let mockLoginStrategyService: MockProxy; let mockRouter: MockProxy; let mockI18nService: MockProxy; @@ -88,7 +88,7 @@ describe("SsoComponent", () => { beforeEach(() => { // Mock Services - mockAuthService = mock(); + mockLoginStrategyService = mock(); mockRouter = mock(); mockI18nService = mock(); @@ -108,7 +108,7 @@ describe("SsoComponent", () => { mockLogService = mock(); mockConfigService = mock(); - // Mock authService.logIn params + // Mock loginStrategyService.logIn params code = "code"; codeVerifier = "codeVerifier"; orgIdFromState = "orgIdFromState"; @@ -167,7 +167,7 @@ describe("SsoComponent", () => { TestBed.configureTestingModule({ declarations: [TestSsoComponent], providers: [ - { provide: AuthService, useValue: mockAuthService }, + { provide: LoginStrategyServiceAbstraction, useValue: mockLoginStrategyService }, { provide: Router, useValue: mockRouter }, { provide: I18nService, useValue: mockI18nService }, { provide: ActivatedRoute, useValue: mockActivatedRoute }, @@ -230,12 +230,12 @@ describe("SsoComponent", () => { mockAcctDecryptionOpts.withMasterPassword, ); - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); it("calls authService.logIn and navigates to the component's defined 2FA route when the auth result requires 2FA and onSuccessfulLoginTwoFactorNavigate is not defined", async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginTwoFactorNavigate).not.toHaveBeenCalled(); @@ -256,7 +256,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginTwoFactorNavigate).toHaveBeenCalledTimes(1); expect(mockRouter.navigate).not.toHaveBeenCalled(); expect(mockLogService.error).not.toHaveBeenCalled(); @@ -267,7 +267,7 @@ describe("SsoComponent", () => { const testChangePasswordOnSuccessfulLogin = () => { it("navigates to the component's defined change password route when onSuccessfulLoginChangePasswordNavigate callback is undefined", async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginChangePasswordNavigate).not.toHaveBeenCalled(); @@ -290,7 +290,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginChangePasswordNavigate).toHaveBeenCalledTimes(1); expect(mockRouter.navigate).not.toHaveBeenCalled(); expect(mockLogService.error).not.toHaveBeenCalled(); @@ -301,7 +301,7 @@ describe("SsoComponent", () => { it(`navigates to the component's defined forcePasswordResetRoute when response.forcePasswordReset is ${reasonString}`, async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginForceResetNavigate).not.toHaveBeenCalled(); @@ -322,7 +322,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginForceResetNavigate).toHaveBeenCalledTimes(1); expect(mockRouter.navigate).not.toHaveBeenCalled(); expect(mockLogService.error).not.toHaveBeenCalled(); @@ -342,12 +342,12 @@ describe("SsoComponent", () => { ); authResult = new AuthResult(); - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); it("navigates to the component's defined trustedDeviceEncRoute route and sets correct flag when onSuccessfulLoginTdeNavigate is undefined ", async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockStateService.setForceSetPasswordReason).toHaveBeenCalledWith( ForceSetPasswordReason.TdeUserWithoutPasswordHasPasswordResetPermission, @@ -379,7 +379,7 @@ describe("SsoComponent", () => { authResult = new AuthResult(); authResult.forcePasswordReset = ForceSetPasswordReason.AdminForcePasswordReset; - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); testForceResetOnSuccessfulLogin(reasonString); @@ -396,13 +396,13 @@ describe("SsoComponent", () => { authResult = new AuthResult(); authResult.forcePasswordReset = ForceSetPasswordReason.None; - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); it("navigates to the component's defined trusted device encryption route when login is successful and no callback is defined", async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockRouter.navigate).toHaveBeenCalledTimes(1); expect(mockRouter.navigate).toHaveBeenCalledWith( [_component.trustedDeviceEncRoute], @@ -417,7 +417,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginTdeNavigate).toHaveBeenCalledTimes(1); @@ -430,7 +430,7 @@ describe("SsoComponent", () => { describe("Set Master Password scenarios", () => { beforeEach(() => { const authResult = new AuthResult(); - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); describe("Given user needs to set a master password", () => { @@ -451,7 +451,7 @@ describe("SsoComponent", () => { ); await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalledTimes(1); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginChangePasswordNavigate).not.toHaveBeenCalled(); expect(mockRouter.navigate).not.toHaveBeenCalledWith([_component.changePasswordRoute], { @@ -477,7 +477,7 @@ describe("SsoComponent", () => { const authResult = new AuthResult(); authResult.forcePasswordReset = forceResetPasswordReason; - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); testForceResetOnSuccessfulLogin(reasonString); @@ -494,13 +494,13 @@ describe("SsoComponent", () => { mockAcctDecryptionOpts.withMasterPassword, ); authResult.forcePasswordReset = ForceSetPasswordReason.None; - mockAuthService.logIn.mockResolvedValue(authResult); + mockLoginStrategyService.logIn.mockResolvedValue(authResult); }); it("calls authService.logIn and navigates to the component's defined success route when the login is successful", async () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalled(); + expect(mockLoginStrategyService.logIn).toHaveBeenCalled(); expect(mockOnSuccessfulLoginNavigate).not.toHaveBeenCalled(); expect(mockOnSuccessfulLogin).not.toHaveBeenCalled(); @@ -516,7 +516,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalled(); + expect(mockLoginStrategyService.logIn).toHaveBeenCalled(); expect(mockOnSuccessfulLogin).toHaveBeenCalledTimes(1); expect(mockOnSuccessfulLoginNavigate).not.toHaveBeenCalled(); @@ -533,7 +533,7 @@ describe("SsoComponent", () => { await _component.logIn(code, codeVerifier, orgIdFromState); - expect(mockAuthService.logIn).toHaveBeenCalled(); + expect(mockLoginStrategyService.logIn).toHaveBeenCalled(); expect(mockOnSuccessfulLoginNavigate).toHaveBeenCalledTimes(1); @@ -547,7 +547,7 @@ describe("SsoComponent", () => { it("calls handleLoginError when an error is thrown during logIn", async () => { const errorMessage = "Key Connector error"; const error = new Error(errorMessage); - mockAuthService.logIn.mockRejectedValue(error); + mockLoginStrategyService.logIn.mockRejectedValue(error); const handleLoginErrorSpy = jest.spyOn(_component, "handleLoginError"); diff --git a/libs/angular/src/auth/components/sso.component.ts b/libs/angular/src/auth/components/sso.component.ts index 53e143955c5..2335f830efa 100644 --- a/libs/angular/src/auth/components/sso.component.ts +++ b/libs/angular/src/auth/components/sso.component.ts @@ -2,11 +2,10 @@ import { Directive } from "@angular/core"; import { ActivatedRoute, NavigationExtras, Router } from "@angular/router"; import { first } from "rxjs/operators"; +import { LoginStrategyServiceAbstraction, SsoLoginCredentials } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; -import { SsoLoginCredentials } from "@bitwarden/common/auth/models/domain/login-credentials"; import { TrustedDeviceUserDecryptionOption } from "@bitwarden/common/auth/models/domain/user-decryption-options/trusted-device-user-decryption-option"; import { SsoPreValidateResponse } from "@bitwarden/common/auth/models/response/sso-pre-validate.response"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; @@ -47,7 +46,7 @@ export class SsoComponent { protected codeChallenge: string; constructor( - protected authService: AuthService, + protected loginStrategyService: LoginStrategyServiceAbstraction, protected router: Router, protected i18nService: I18nService, protected route: ActivatedRoute, @@ -187,7 +186,7 @@ export class SsoComponent { this.redirectUri, orgSsoIdentifier, ); - this.formPromise = this.authService.logIn(credentials); + this.formPromise = this.loginStrategyService.logIn(credentials); const authResult = await this.formPromise; const acctDecryptionOpts: AccountDecryptionOptions = diff --git a/libs/angular/src/auth/components/two-factor.component.spec.ts b/libs/angular/src/auth/components/two-factor.component.spec.ts index c7e03aca194..93916644e3c 100644 --- a/libs/angular/src/auth/components/two-factor.component.spec.ts +++ b/libs/angular/src/auth/components/two-factor.component.spec.ts @@ -5,8 +5,8 @@ import { MockProxy, mock } from "jest-mock-extended"; // eslint-disable-next-line no-restricted-imports import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; @@ -43,7 +43,7 @@ describe("TwoFactorComponent", () => { let fixture: ComponentFixture; // Mock Services - let mockAuthService: MockProxy; + let mockLoginStrategyService: MockProxy; let mockRouter: MockProxy; let mockI18nService: MockProxy; let mockApiService: MockProxy; @@ -69,7 +69,7 @@ describe("TwoFactorComponent", () => { }; beforeEach(() => { - mockAuthService = mock(); + mockLoginStrategyService = mock(); mockRouter = mock(); mockI18nService = mock(); mockApiService = mock(); @@ -129,7 +129,7 @@ describe("TwoFactorComponent", () => { TestBed.configureTestingModule({ declarations: [TestTwoFactorComponent], providers: [ - { provide: AuthService, useValue: mockAuthService }, + { provide: LoginStrategyServiceAbstraction, useValue: mockLoginStrategyService }, { provide: Router, useValue: mockRouter }, { provide: I18nService, useValue: mockI18nService }, { provide: ApiService, useValue: mockApiService }, @@ -216,13 +216,13 @@ describe("TwoFactorComponent", () => { it("calls authService.logInTwoFactor with correct parameters when form is submitted", async () => { // Arrange - mockAuthService.logInTwoFactor.mockResolvedValue(new AuthResult()); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(new AuthResult()); // Act await component.doSubmit(); // Assert - expect(mockAuthService.logInTwoFactor).toHaveBeenCalledWith( + expect(mockLoginStrategyService.logInTwoFactor).toHaveBeenCalledWith( new TokenTwoFactorRequest(component.selectedProviderType, token, remember), captchaToken, ); @@ -234,7 +234,7 @@ describe("TwoFactorComponent", () => { const authResult = new AuthResult(); authResult.captchaSiteKey = captchaSiteKey; - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); // Note: the any casts are required b/c typescript cant recognize that // handleCaptureRequired is a method on TwoFactorComponent b/c it is inherited @@ -254,7 +254,7 @@ describe("TwoFactorComponent", () => { it("calls onSuccessfulLogin when defined", async () => { // Arrange component.onSuccessfulLogin = jest.fn().mockResolvedValue(undefined); - mockAuthService.logInTwoFactor.mockResolvedValue(new AuthResult()); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(new AuthResult()); // Act await component.doSubmit(); @@ -265,7 +265,7 @@ describe("TwoFactorComponent", () => { it("calls loginService.clearValues() when login is successful", async () => { // Arrange - mockAuthService.logInTwoFactor.mockResolvedValue(new AuthResult()); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(new AuthResult()); // spy on loginService.clearValues const clearValuesSpy = jest.spyOn(mockLoginService, "clearValues"); @@ -279,7 +279,7 @@ describe("TwoFactorComponent", () => { describe("Set Master Password scenarios", () => { beforeEach(() => { const authResult = new AuthResult(); - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); }); describe("Given user needs to set a master password", () => { @@ -323,7 +323,7 @@ describe("TwoFactorComponent", () => { const authResult = new AuthResult(); authResult.forcePasswordReset = forceResetPasswordReason; - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); }); testForceResetOnSuccessfulLogin(reasonString); @@ -333,7 +333,7 @@ describe("TwoFactorComponent", () => { it("calls onSuccessfulLoginNavigate when the callback is defined", async () => { // Arrange component.onSuccessfulLoginNavigate = jest.fn().mockResolvedValue(undefined); - mockAuthService.logInTwoFactor.mockResolvedValue(new AuthResult()); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(new AuthResult()); // Act await component.doSubmit(); @@ -343,7 +343,7 @@ describe("TwoFactorComponent", () => { }); it("navigates to the component's defined success route when the login is successful and onSuccessfulLoginNavigate is undefined", async () => { - mockAuthService.logInTwoFactor.mockResolvedValue(new AuthResult()); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(new AuthResult()); // Act await component.doSubmit(); @@ -386,7 +386,7 @@ describe("TwoFactorComponent", () => { ); const authResult = new AuthResult(); - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); }); it("navigates to the component's defined trusted device encryption route and sets correct flag when user doesn't have a MP and key connector isn't enabled", async () => { @@ -422,7 +422,7 @@ describe("TwoFactorComponent", () => { const authResult = new AuthResult(); authResult.forcePasswordReset = forceResetPasswordReason; - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); }); testForceResetOnSuccessfulLogin(reasonString); @@ -438,7 +438,7 @@ describe("TwoFactorComponent", () => { authResult = new AuthResult(); authResult.forcePasswordReset = ForceSetPasswordReason.None; - mockAuthService.logInTwoFactor.mockResolvedValue(authResult); + mockLoginStrategyService.logInTwoFactor.mockResolvedValue(authResult); }); it("navigates to the component's defined trusted device encryption route when login is successful and onSuccessfulLoginTdeNavigate is undefined", async () => { diff --git a/libs/angular/src/auth/components/two-factor.component.ts b/libs/angular/src/auth/components/two-factor.component.ts index 6e63e569c68..27c702e568f 100644 --- a/libs/angular/src/auth/components/two-factor.component.ts +++ b/libs/angular/src/auth/components/two-factor.component.ts @@ -5,8 +5,8 @@ import { first } from "rxjs/operators"; // eslint-disable-next-line no-restricted-imports import { WINDOW } from "@bitwarden/angular/services/injection-tokens"; +import { LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { LoginService } from "@bitwarden/common/auth/abstractions/login.service"; import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; @@ -70,7 +70,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI } constructor( - protected authService: AuthService, + protected loginStrategyService: LoginStrategyServiceAbstraction, protected router: Router, protected i18nService: I18nService, protected apiService: ApiService, @@ -243,7 +243,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI } async doSubmit() { - this.formPromise = this.authService.logInTwoFactor( + this.formPromise = this.loginStrategyService.logInTwoFactor( new TokenTwoFactorRequest(this.selectedProviderType, this.token, this.remember), this.captchaToken, ); @@ -424,7 +424,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI return; } - if (this.authService.email == null) { + if (this.loginStrategyService.email == null) { this.platformUtilsService.showToast( "error", this.i18nService.t("errorOccurred"), @@ -435,12 +435,12 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI try { const request = new TwoFactorEmailRequest(); - request.email = this.authService.email; - request.masterPasswordHash = this.authService.masterPasswordHash; - request.ssoEmail2FaSessionToken = this.authService.ssoEmail2FaSessionToken; + request.email = this.loginStrategyService.email; + request.masterPasswordHash = this.loginStrategyService.masterPasswordHash; + request.ssoEmail2FaSessionToken = this.loginStrategyService.ssoEmail2FaSessionToken; request.deviceIdentifier = await this.appIdService.getAppId(); - request.authRequestAccessCode = this.authService.accessCode; - request.authRequestId = this.authService.authRequestId; + request.authRequestAccessCode = this.loginStrategyService.accessCode; + request.authRequestId = this.loginStrategyService.authRequestId; this.emailPromise = this.apiService.postTwoFactorEmail(request); await this.emailPromise; if (doToast) { @@ -476,15 +476,18 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI get authing(): boolean { return ( - this.authService.authingWithPassword() || - this.authService.authingWithSso() || - this.authService.authingWithUserApiKey() || - this.authService.authingWithPasswordless() + this.loginStrategyService.authingWithPassword() || + this.loginStrategyService.authingWithSso() || + this.loginStrategyService.authingWithUserApiKey() || + this.loginStrategyService.authingWithPasswordless() ); } get needsLock(): boolean { - return this.authService.authingWithSso() || this.authService.authingWithUserApiKey(); + return ( + this.loginStrategyService.authingWithSso() || + this.loginStrategyService.authingWithUserApiKey() + ); } launchDuoFrameless() { diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index b05bc956354..b7f7fd5549e 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1,6 +1,11 @@ import { LOCALE_ID, NgModule } from "@angular/core"; -import { PinCryptoServiceAbstraction, PinCryptoService } from "@bitwarden/auth/common"; +import { + PinCryptoServiceAbstraction, + PinCryptoService, + LoginStrategyServiceAbstraction, + LoginStrategyService, +} from "@bitwarden/auth/common"; import { AvatarUpdateService as AccountUpdateServiceAbstraction } from "@bitwarden/common/abstractions/account/avatar-update.service"; import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service"; import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service"; @@ -274,6 +279,16 @@ import { ModalService } from "./modal.service"; { provide: AuthServiceAbstraction, useClass: AuthService, + deps: [ + MessagingServiceAbstraction, + CryptoServiceAbstraction, + ApiServiceAbstraction, + StateServiceAbstraction, + ], + }, + { + provide: LoginStrategyServiceAbstraction, + useClass: LoginStrategyService, deps: [ CryptoServiceAbstraction, ApiServiceAbstraction, @@ -747,7 +762,7 @@ import { ModalService } from "./modal.service"; { provide: AnonymousHubServiceAbstraction, useClass: AnonymousHubService, - deps: [EnvironmentServiceAbstraction, AuthServiceAbstraction, LogService], + deps: [EnvironmentServiceAbstraction, LoginStrategyServiceAbstraction, LogService], }, { provide: ValidationServiceAbstraction, @@ -828,7 +843,7 @@ import { ModalService } from "./modal.service"; useClass: WebAuthnLoginService, deps: [ WebAuthnLoginApiServiceAbstraction, - AuthServiceAbstraction, + LoginStrategyServiceAbstraction, ConfigServiceAbstraction, WebAuthnLoginPrfCryptoServiceAbstraction, WINDOW, diff --git a/libs/auth/src/common/abstractions/index.ts b/libs/auth/src/common/abstractions/index.ts index 5bd8a69d730..674a068a748 100644 --- a/libs/auth/src/common/abstractions/index.ts +++ b/libs/auth/src/common/abstractions/index.ts @@ -1 +1,2 @@ export * from "./pin-crypto.service.abstraction"; +export * from "./login-strategy.service"; diff --git a/libs/auth/src/common/abstractions/login-strategy.service.ts b/libs/auth/src/common/abstractions/login-strategy.service.ts new file mode 100644 index 00000000000..25e812eca78 --- /dev/null +++ b/libs/auth/src/common/abstractions/login-strategy.service.ts @@ -0,0 +1,48 @@ +import { Observable } from "rxjs"; + +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; +import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response"; +import { MasterKey } from "@bitwarden/common/types/key"; + +import { + UserApiLoginCredentials, + PasswordLoginCredentials, + SsoLoginCredentials, + AuthRequestLoginCredentials, + WebAuthnLoginCredentials, +} from "../models/domain/login-credentials"; + +export abstract class LoginStrategyServiceAbstraction { + masterPasswordHash: string; + email: string; + accessCode: string; + authRequestId: string; + ssoEmail2FaSessionToken: string; + + logIn: ( + credentials: + | UserApiLoginCredentials + | PasswordLoginCredentials + | SsoLoginCredentials + | AuthRequestLoginCredentials + | WebAuthnLoginCredentials, + ) => Promise; + logInTwoFactor: ( + twoFactor: TokenTwoFactorRequest, + captchaResponse: string, + ) => Promise; + makePreloginKey: (masterPassword: string, email: string) => Promise; + authingWithUserApiKey: () => boolean; + authingWithSso: () => boolean; + authingWithPassword: () => boolean; + authingWithPasswordless: () => boolean; + authResponsePushNotification: (notification: AuthRequestPushNotification) => Promise; + passwordlessLogin: ( + id: string, + key: string, + requestApproved: boolean, + ) => Promise; + getPushNotificationObs$: () => Observable; +} diff --git a/libs/common/src/auth/login-strategies/auth-request-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts similarity index 78% rename from libs/common/src/auth/login-strategies/auth-request-login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts index 137ccffb617..607366646a2 100644 --- a/libs/common/src/auth/login-strategies/auth-request-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts @@ -1,21 +1,22 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { Utils } from "../../platform/misc/utils"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { CsprngArray } from "../../types/csprng"; -import { MasterKey, UserKey } from "../../types/key"; -import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; + import { AuthRequestLoginCredentials } from "../models/domain/login-credentials"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; import { AuthRequestLoginStrategy } from "./auth-request-login.strategy"; import { identityTokenResponseFactory } from "./login.strategy.spec"; diff --git a/libs/common/src/auth/login-strategies/auth-request-login.strategy.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts similarity index 73% rename from libs/common/src/auth/login-strategies/auth-request-login.strategy.ts rename to libs/auth/src/common/login-strategies/auth-request-login.strategy.ts index 06aa750d8eb..9da2e15259c 100644 --- a/libs/common/src/auth/login-strategies/auth-request-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts @@ -1,18 +1,19 @@ -import { ApiService } from "../../abstractions/api.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { AuthResult } from "../models/domain/auth-result"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; + import { AuthRequestLoginCredentials } from "../models/domain/login-credentials"; -import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; import { LoginStrategy } from "./login.strategy"; diff --git a/libs/common/src/auth/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts similarity index 82% rename from libs/common/src/auth/login-strategies/login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/login.strategy.spec.ts index f07c051a831..3639ed096ab 100644 --- a/libs/common/src/auth/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -1,43 +1,44 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { Utils } from "../../platform/misc/utils"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { IdentityCaptchaResponse } from "@bitwarden/common/auth/models/response/identity-captcha.response"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response"; +import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Account, - AccountDecryptionOptions, - AccountKeys, AccountProfile, AccountTokens, -} from "../../platform/models/domain/account"; -import { EncString } from "../../platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; + AccountKeys, + AccountDecryptionOptions, +} from "@bitwarden/common/platform/models/domain/account"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { - PasswordStrengthService, PasswordStrengthServiceAbstraction, -} from "../../tools/password-strength"; -import { CsprngArray } from "../../types/csprng"; -import { UserKey, MasterKey, DeviceKey } from "../../types/key"; -import { AuthService } from "../abstractions/auth.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { TwoFactorProviderType } from "../enums/two-factor-provider-type"; -import { AuthResult } from "../models/domain/auth-result"; -import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason"; + PasswordStrengthService, +} from "@bitwarden/common/tools/password-strength"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { UserKey, MasterKey, DeviceKey } from "@bitwarden/common/types/key"; + +import { LoginStrategyServiceAbstraction } from "../abstractions/login-strategy.service"; import { PasswordLoginCredentials } from "../models/domain/login-credentials"; -import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; -import { MasterPasswordPolicyResponse } from "../models/response/master-password-policy.response"; -import { IUserDecryptionOptionsServerResponse } from "../models/response/user-decryption-options/user-decryption-options.response"; import { PasswordLoginStrategy } from "./password-login.strategy"; @@ -93,6 +94,7 @@ export function identityTokenResponseFactory( // TODO: add tests for latest changes to base class for TDE describe("LoginStrategy", () => { + let loginStrategyService: MockProxy; let cryptoService: MockProxy; let apiService: MockProxy; let tokenService: MockProxy; @@ -102,7 +104,6 @@ describe("LoginStrategy", () => { let logService: MockProxy; let stateService: MockProxy; let twoFactorService: MockProxy; - let authService: MockProxy; let policyService: MockProxy; let passwordStrengthService: MockProxy; @@ -110,6 +111,7 @@ describe("LoginStrategy", () => { let credentials: PasswordLoginCredentials; beforeEach(async () => { + loginStrategyService = mock(); cryptoService = mock(); apiService = mock(); tokenService = mock(); @@ -119,7 +121,6 @@ describe("LoginStrategy", () => { logService = mock(); stateService = mock(); twoFactorService = mock(); - authService = mock(); policyService = mock(); passwordStrengthService = mock(); @@ -139,7 +140,7 @@ describe("LoginStrategy", () => { twoFactorService, passwordStrengthService, policyService, - authService, + loginStrategyService, ); credentials = new PasswordLoginCredentials(email, masterPassword); }); diff --git a/libs/common/src/auth/login-strategies/login.strategy.ts b/libs/auth/src/common/login-strategies/login.strategy.ts similarity index 76% rename from libs/common/src/auth/login-strategies/login.strategy.ts rename to libs/auth/src/common/login-strategies/login.strategy.ts index 03c5701dde6..2c8d9c94e46 100644 --- a/libs/common/src/auth/login-strategies/login.strategy.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.ts @@ -1,40 +1,41 @@ -import { ApiService } from "../../abstractions/api.service"; -import { ClientType } from "../../enums"; -import { KeysRequest } from "../../models/request/keys.request"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { DeviceRequest } from "@bitwarden/common/auth/models/request/identity-token/device.request"; +import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; +import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { UserApiTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/user-api-token.request"; +import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/webauthn-login-token.request"; +import { IdentityCaptchaResponse } from "@bitwarden/common/auth/models/response/identity-captcha.response"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { ClientType } from "@bitwarden/common/enums"; +import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { - Account, - AccountDecryptionOptions, AccountKeys, + Account, AccountProfile, AccountTokens, -} from "../../platform/models/domain/account"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { TwoFactorProviderType } from "../enums/two-factor-provider-type"; -import { AuthResult } from "../models/domain/auth-result"; -import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason"; + AccountDecryptionOptions, +} from "@bitwarden/common/platform/models/domain/account"; + import { - AuthRequestLoginCredentials, + UserApiLoginCredentials, PasswordLoginCredentials, SsoLoginCredentials, - UserApiLoginCredentials, + AuthRequestLoginCredentials, WebAuthnLoginCredentials, } from "../models/domain/login-credentials"; -import { DeviceRequest } from "../models/request/identity-token/device.request"; -import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request"; -import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request"; -import { WebAuthnLoginTokenRequest } from "../models/request/identity-token/webauthn-login-token.request"; -import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; type IdentityResponse = IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse; diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts similarity index 77% rename from libs/common/src/auth/login-strategies/password-login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/password-login.strategy.spec.ts index fd0e49b923a..aa7a530fbb4 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts @@ -1,31 +1,32 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { HashPurpose } from "../../platform/enums"; -import { Utils } from "../../platform/misc/utils"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { MasterPasswordPolicyResponse } from "@bitwarden/common/auth/models/response/master-password-policy.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { HashPurpose } from "@bitwarden/common/platform/enums"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { - PasswordStrengthService, PasswordStrengthServiceAbstraction, -} from "../../tools/password-strength"; -import { CsprngArray } from "../../types/csprng"; -import { MasterKey, UserKey } from "../../types/key"; -import { AuthService } from "../abstractions/auth.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { TwoFactorProviderType } from "../enums/two-factor-provider-type"; -import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason"; + PasswordStrengthService, +} from "@bitwarden/common/tools/password-strength"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { MasterKey, UserKey } from "@bitwarden/common/types/key"; + +import { LoginStrategyServiceAbstraction } from "../abstractions"; import { PasswordLoginCredentials } from "../models/domain/login-credentials"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; -import { MasterPasswordPolicyResponse } from "../models/response/master-password-policy.response"; import { identityTokenResponseFactory } from "./login.strategy.spec"; import { PasswordLoginStrategy } from "./password-login.strategy"; @@ -46,6 +47,7 @@ const masterPasswordPolicy = new MasterPasswordPolicyResponse({ }); describe("PasswordLoginStrategy", () => { + let loginStrategyService: MockProxy; let cryptoService: MockProxy; let apiService: MockProxy; let tokenService: MockProxy; @@ -55,7 +57,6 @@ describe("PasswordLoginStrategy", () => { let logService: MockProxy; let stateService: MockProxy; let twoFactorService: MockProxy; - let authService: MockProxy; let policyService: MockProxy; let passwordStrengthService: MockProxy; @@ -64,6 +65,7 @@ describe("PasswordLoginStrategy", () => { let tokenResponse: IdentityTokenResponse; beforeEach(async () => { + loginStrategyService = mock(); cryptoService = mock(); apiService = mock(); tokenService = mock(); @@ -73,14 +75,13 @@ describe("PasswordLoginStrategy", () => { logService = mock(); stateService = mock(); twoFactorService = mock(); - authService = mock(); policyService = mock(); passwordStrengthService = mock(); appIdService.getAppId.mockResolvedValue(deviceId); tokenService.decodeToken.mockResolvedValue({}); - authService.makePreloginKey.mockResolvedValue(masterKey); + loginStrategyService.makePreloginKey.mockResolvedValue(masterKey); cryptoService.hashMasterKey .calledWith(masterPassword, expect.anything(), undefined) @@ -103,7 +104,7 @@ describe("PasswordLoginStrategy", () => { twoFactorService, passwordStrengthService, policyService, - authService, + loginStrategyService, ); credentials = new PasswordLoginCredentials(email, masterPassword); tokenResponse = identityTokenResponseFactory(masterPasswordPolicy); diff --git a/libs/common/src/auth/login-strategies/password-login.strategy.ts b/libs/auth/src/common/login-strategies/password-login.strategy.ts similarity index 72% rename from libs/common/src/auth/login-strategies/password-login.strategy.ts rename to libs/auth/src/common/login-strategies/password-login.strategy.ts index d3f0a0be034..ddbd47465ee 100644 --- a/libs/common/src/auth/login-strategies/password-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.ts @@ -1,26 +1,27 @@ -import { ApiService } from "../../abstractions/api.service"; -import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; -import { MasterPasswordPolicyOptions } from "../../admin-console/models/domain/master-password-policy-options"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { HashPurpose } from "../../platform/enums"; -import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; -import { MasterKey } from "../../types/key"; -import { AuthService } from "../abstractions/auth.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { AuthResult } from "../models/domain/auth-result"; -import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { IdentityCaptchaResponse } from "@bitwarden/common/auth/models/response/identity-captcha.response"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { HashPurpose } from "@bitwarden/common/platform/enums"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; +import { MasterKey } from "@bitwarden/common/types/key"; + +import { LoginStrategyServiceAbstraction } from "../abstractions"; import { PasswordLoginCredentials } from "../models/domain/login-credentials"; -import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response"; import { LoginStrategy } from "./login.strategy"; @@ -56,7 +57,7 @@ export class PasswordLoginStrategy extends LoginStrategy { twoFactorService: TwoFactorService, private passwordStrengthService: PasswordStrengthServiceAbstraction, private policyService: PolicyService, - private authService: AuthService, + private loginStrategyService: LoginStrategyServiceAbstraction, ) { super( cryptoService, @@ -94,7 +95,7 @@ export class PasswordLoginStrategy extends LoginStrategy { override async logIn(credentials: PasswordLoginCredentials) { const { email, masterPassword, captchaToken, twoFactor } = credentials; - this.masterKey = await this.authService.makePreloginKey(masterPassword, email); + this.masterKey = await this.loginStrategyService.makePreloginKey(masterPassword, email); // Hash the password early (before authentication) so we don't persist it in memory in plaintext this.localMasterKeyHash = await this.cryptoService.hashMasterKey( diff --git a/libs/common/src/auth/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts similarity index 89% rename from libs/common/src/auth/login-strategies/sso-login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index 2b024d95bce..7c0e78922f1 100644 --- a/libs/common/src/auth/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -1,25 +1,26 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { I18nService } from "../../platform/abstractions/i18n.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { Utils } from "../../platform/misc/utils"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { CsprngArray } from "../../types/csprng"; -import { DeviceKey, UserKey, MasterKey } from "../../types/key"; -import { AuthRequestCryptoServiceAbstraction } from "../abstractions/auth-request-crypto.service.abstraction"; -import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction"; -import { KeyConnectorService } from "../abstractions/key-connector.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; +import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key"; + import { SsoLoginCredentials } from "../models/domain/login-credentials"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IUserDecryptionOptionsServerResponse } from "../models/response/user-decryption-options/user-decryption-options.response"; import { identityTokenResponseFactory } from "./login.strategy.spec"; import { SsoLoginStrategy } from "./sso-login.strategy"; diff --git a/libs/common/src/auth/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts similarity index 85% rename from libs/common/src/auth/login-strategies/sso-login.strategy.ts rename to libs/auth/src/common/login-strategies/sso-login.strategy.ts index b57329f7f90..6122833d230 100644 --- a/libs/common/src/auth/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -1,23 +1,24 @@ -import { ApiService } from "../../abstractions/api.service"; -import { AuthRequestResponse } from "../../auth/models/response/auth-request.response"; -import { HttpStatusCode } from "../../enums"; -import { ErrorResponse } from "../../models/response/error.response"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { I18nService } from "../../platform/abstractions/i18n.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { AuthRequestCryptoServiceAbstraction } from "../abstractions/auth-request-crypto.service.abstraction"; -import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction"; -import { KeyConnectorService } from "../abstractions/key-connector.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { ForceSetPasswordReason } from "../models/domain/force-set-password-reason"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; +import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; +import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request"; +import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { HttpStatusCode } from "@bitwarden/common/enums"; +import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; + import { SsoLoginCredentials } from "../models/domain/login-credentials"; -import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; import { LoginStrategy } from "./login.strategy"; diff --git a/libs/common/src/auth/login-strategies/user-api-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts similarity index 79% rename from libs/common/src/auth/login-strategies/user-api-login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts index 71f7776beef..eb240a6a02b 100644 --- a/libs/common/src/auth/login-strategies/user-api-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts @@ -1,20 +1,21 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { EnvironmentService } from "../../platform/abstractions/environment.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { Utils } from "../../platform/misc/utils"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { CsprngArray } from "../../types/csprng"; -import { UserKey, MasterKey } from "../../types/key"; -import { KeyConnectorService } from "../abstractions/key-connector.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { CsprngArray } from "@bitwarden/common/types/csprng"; +import { UserKey, MasterKey } from "@bitwarden/common/types/key"; + import { UserApiLoginCredentials } from "../models/domain/login-credentials"; import { identityTokenResponseFactory } from "./login.strategy.spec"; diff --git a/libs/common/src/auth/login-strategies/user-api-login.strategy.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.ts similarity index 67% rename from libs/common/src/auth/login-strategies/user-api-login.strategy.ts rename to libs/auth/src/common/login-strategies/user-api-login.strategy.ts index 9849bf90109..a9fbf045b17 100644 --- a/libs/common/src/auth/login-strategies/user-api-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.ts @@ -1,17 +1,18 @@ -import { ApiService } from "../../abstractions/api.service"; -import { TokenService } from "../../auth/abstractions/token.service"; -import { TwoFactorService } from "../../auth/abstractions/two-factor.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { EnvironmentService } from "../../platform/abstractions/environment.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { KeyConnectorService } from "../abstractions/key-connector.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { UserApiTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/user-api-token.request"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; + import { UserApiLoginCredentials } from "../models/domain/login-credentials"; -import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; import { LoginStrategy } from "./login.strategy"; diff --git a/libs/common/src/auth/login-strategies/webauthn-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts similarity index 89% rename from libs/common/src/auth/login-strategies/webauthn-login.strategy.spec.ts rename to libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts index a8236ab020a..cbe7084ccc9 100644 --- a/libs/common/src/auth/login-strategies/webauthn-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.spec.ts @@ -1,22 +1,23 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { ApiService } from "../../abstractions/api.service"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; -import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { LogService } from "../../platform/abstractions/log.service"; -import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; -import { StateService } from "../../platform/abstractions/state.service"; -import { Utils } from "../../platform/misc/utils"; -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { PrfKey, UserKey } from "../../types/key"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; -import { AuthResult } from "../models/domain/auth-result"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { IUserDecryptionOptionsServerResponse } from "@bitwarden/common/auth/models/response/user-decryption-options/user-decryption-options.response"; +import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { PrfKey, UserKey } from "@bitwarden/common/types/key"; + import { WebAuthnLoginCredentials } from "../models/domain/login-credentials"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; -import { IUserDecryptionOptionsServerResponse } from "../models/response/user-decryption-options/user-decryption-options.response"; -import { WebAuthnLoginAssertionResponseRequest } from "../services/webauthn-login/request/webauthn-login-assertion-response.request"; import { identityTokenResponseFactory } from "./login.strategy.spec"; import { WebAuthnLoginStrategy } from "./webauthn-login.strategy"; diff --git a/libs/common/src/auth/login-strategies/webauthn-login.strategy.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts similarity index 83% rename from libs/common/src/auth/login-strategies/webauthn-login.strategy.ts rename to libs/auth/src/common/login-strategies/webauthn-login.strategy.ts index b3e2e456bd1..c3fbf28b8e5 100644 --- a/libs/common/src/auth/login-strategies/webauthn-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts @@ -1,9 +1,10 @@ -import { SymmetricCryptoKey } from "../../platform/models/domain/symmetric-crypto-key"; -import { UserKey } from "../../types/key"; -import { AuthResult } from "../models/domain/auth-result"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/webauthn-login-token.request"; +import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { UserKey } from "@bitwarden/common/types/key"; + import { WebAuthnLoginCredentials } from "../models/domain/login-credentials"; -import { WebAuthnLoginTokenRequest } from "../models/request/identity-token/webauthn-login-token.request"; -import { IdentityTokenResponse } from "../models/response/identity-token.response"; import { LoginStrategy } from "./login.strategy"; diff --git a/libs/auth/src/common/models/domain/index.ts b/libs/auth/src/common/models/domain/index.ts index 7ed98e0c027..c3166f737d6 100644 --- a/libs/auth/src/common/models/domain/index.ts +++ b/libs/auth/src/common/models/domain/index.ts @@ -1 +1,2 @@ export * from "./rotateable-key-set"; +export * from "./login-credentials"; diff --git a/libs/common/src/auth/models/domain/login-credentials.ts b/libs/auth/src/common/models/domain/login-credentials.ts similarity index 71% rename from libs/common/src/auth/models/domain/login-credentials.ts rename to libs/auth/src/common/models/domain/login-credentials.ts index a369d876132..93cb07e2b1f 100644 --- a/libs/common/src/auth/models/domain/login-credentials.ts +++ b/libs/auth/src/common/models/domain/login-credentials.ts @@ -1,8 +1,8 @@ -import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; -import { UserKey, MasterKey } from "../../../types/key"; -import { AuthenticationType } from "../../enums/authentication-type"; -import { WebAuthnLoginAssertionResponseRequest } from "../../services/webauthn-login/request/webauthn-login-assertion-response.request"; -import { TokenTwoFactorRequest } from "../request/identity-token/token-two-factor.request"; +import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { UserKey, MasterKey } from "@bitwarden/common/types/key"; export class PasswordLoginCredentials { readonly type = AuthenticationType.Password; diff --git a/libs/auth/src/common/services/index.ts b/libs/auth/src/common/services/index.ts index 688eefffd8e..9fb652d40e2 100644 --- a/libs/auth/src/common/services/index.ts +++ b/libs/auth/src/common/services/index.ts @@ -1 +1,2 @@ export * from "./pin-crypto/pin-crypto.service.implementation"; +export * from "./login-strategies/login-strategy.service"; diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts new file mode 100644 index 00000000000..b94c6a150e1 --- /dev/null +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -0,0 +1,359 @@ +import { Observable, Subject } from "rxjs"; + +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AuthRequestCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-crypto.service.abstraction"; +import { DeviceTrustCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust-crypto.service.abstraction"; +import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { AuthenticationType } from "@bitwarden/common/auth/enums/authentication-type"; +import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; +import { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; +import { PasswordlessAuthRequest } from "@bitwarden/common/auth/models/request/passwordless-auth.request"; +import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; +import { PreloginRequest } from "@bitwarden/common/models/request/prelogin.request"; +import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; +import { AuthRequestPushNotification } from "@bitwarden/common/models/response/notification.response"; +import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; +import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { KdfType } from "@bitwarden/common/platform/enums"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; +import { MasterKey } from "@bitwarden/common/types/key"; + +import { LoginStrategyServiceAbstraction } from "../../abstractions"; +import { AuthRequestLoginStrategy } from "../../login-strategies/auth-request-login.strategy"; +import { PasswordLoginStrategy } from "../../login-strategies/password-login.strategy"; +import { SsoLoginStrategy } from "../../login-strategies/sso-login.strategy"; +import { UserApiLoginStrategy } from "../../login-strategies/user-api-login.strategy"; +import { WebAuthnLoginStrategy } from "../../login-strategies/webauthn-login.strategy"; +import { + UserApiLoginCredentials, + PasswordLoginCredentials, + SsoLoginCredentials, + AuthRequestLoginCredentials, + WebAuthnLoginCredentials, +} from "../../models"; + +const sessionTimeoutLength = 2 * 60 * 1000; // 2 minutes + +export class LoginStrategyService implements LoginStrategyServiceAbstraction { + get email(): string { + if ( + this.logInStrategy instanceof PasswordLoginStrategy || + this.logInStrategy instanceof AuthRequestLoginStrategy || + this.logInStrategy instanceof SsoLoginStrategy + ) { + return this.logInStrategy.email; + } + + return null; + } + + get masterPasswordHash(): string { + return this.logInStrategy instanceof PasswordLoginStrategy + ? this.logInStrategy.masterPasswordHash + : null; + } + + get accessCode(): string { + return this.logInStrategy instanceof AuthRequestLoginStrategy + ? this.logInStrategy.accessCode + : null; + } + + get authRequestId(): string { + return this.logInStrategy instanceof AuthRequestLoginStrategy + ? this.logInStrategy.authRequestId + : null; + } + + get ssoEmail2FaSessionToken(): string { + return this.logInStrategy instanceof SsoLoginStrategy + ? this.logInStrategy.ssoEmail2FaSessionToken + : null; + } + + private logInStrategy: + | UserApiLoginStrategy + | PasswordLoginStrategy + | SsoLoginStrategy + | AuthRequestLoginStrategy + | WebAuthnLoginStrategy; + private sessionTimeout: any; + + private pushNotificationSubject = new Subject(); + + constructor( + protected cryptoService: CryptoService, + protected apiService: ApiService, + protected tokenService: TokenService, + protected appIdService: AppIdService, + protected platformUtilsService: PlatformUtilsService, + protected messagingService: MessagingService, + protected logService: LogService, + protected keyConnectorService: KeyConnectorService, + protected environmentService: EnvironmentService, + protected stateService: StateService, + protected twoFactorService: TwoFactorService, + protected i18nService: I18nService, + protected encryptService: EncryptService, + protected passwordStrengthService: PasswordStrengthServiceAbstraction, + protected policyService: PolicyService, + protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, + protected authReqCryptoService: AuthRequestCryptoServiceAbstraction, + ) {} + + async logIn( + credentials: + | UserApiLoginCredentials + | PasswordLoginCredentials + | SsoLoginCredentials + | AuthRequestLoginCredentials + | WebAuthnLoginCredentials, + ): Promise { + this.clearState(); + + let strategy: + | UserApiLoginStrategy + | PasswordLoginStrategy + | SsoLoginStrategy + | AuthRequestLoginStrategy + | WebAuthnLoginStrategy; + + switch (credentials.type) { + case AuthenticationType.Password: + strategy = new PasswordLoginStrategy( + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + this.passwordStrengthService, + this.policyService, + this, + ); + break; + case AuthenticationType.Sso: + strategy = new SsoLoginStrategy( + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + this.keyConnectorService, + this.deviceTrustCryptoService, + this.authReqCryptoService, + this.i18nService, + ); + break; + case AuthenticationType.UserApi: + strategy = new UserApiLoginStrategy( + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + this.environmentService, + this.keyConnectorService, + ); + break; + case AuthenticationType.AuthRequest: + strategy = new AuthRequestLoginStrategy( + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + this.deviceTrustCryptoService, + ); + break; + case AuthenticationType.WebAuthn: + strategy = new WebAuthnLoginStrategy( + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + ); + break; + } + + // Note: Do not set the credentials object directly on the strategy. They are + // created in the popup and can cause DeadObject references on Firefox. + const result = await strategy.logIn(credentials as any); + + if (result?.requiresTwoFactor) { + this.saveState(strategy); + } + + return result; + } + + async logInTwoFactor( + twoFactor: TokenTwoFactorRequest, + captchaResponse: string, + ): Promise { + if (this.logInStrategy == null) { + throw new Error(this.i18nService.t("sessionTimeout")); + } + + try { + const result = await this.logInStrategy.logInTwoFactor(twoFactor, captchaResponse); + + // Only clear state if 2FA token has been accepted, otherwise we need to be able to try again + if (!result.requiresTwoFactor && !result.requiresCaptcha) { + this.clearState(); + } + return result; + } catch (e) { + // API exceptions are okay, but if there are any unhandled client-side errors then clear state to be safe + if (!(e instanceof ErrorResponse)) { + this.clearState(); + } + throw e; + } + } + + authingWithUserApiKey(): boolean { + return this.logInStrategy instanceof UserApiLoginStrategy; + } + + authingWithSso(): boolean { + return this.logInStrategy instanceof SsoLoginStrategy; + } + + authingWithPassword(): boolean { + return this.logInStrategy instanceof PasswordLoginStrategy; + } + + authingWithPasswordless(): boolean { + return this.logInStrategy instanceof AuthRequestLoginStrategy; + } + + async makePreloginKey(masterPassword: string, email: string): Promise { + email = email.trim().toLowerCase(); + let kdf: KdfType = null; + let kdfConfig: KdfConfig = null; + try { + const preloginResponse = await this.apiService.postPrelogin(new PreloginRequest(email)); + if (preloginResponse != null) { + kdf = preloginResponse.kdf; + kdfConfig = new KdfConfig( + preloginResponse.kdfIterations, + preloginResponse.kdfMemory, + preloginResponse.kdfParallelism, + ); + } + } catch (e) { + if (e == null || e.statusCode !== 404) { + throw e; + } + } + return await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig); + } + + async authResponsePushNotification(notification: AuthRequestPushNotification): Promise { + this.pushNotificationSubject.next(notification.id); + } + + getPushNotificationObs$(): Observable { + return this.pushNotificationSubject.asObservable(); + } + + async passwordlessLogin( + id: string, + key: string, + requestApproved: boolean, + ): Promise { + const pubKey = Utils.fromB64ToArray(key); + + const masterKey = await this.cryptoService.getMasterKey(); + let keyToEncrypt; + let encryptedMasterKeyHash = null; + + if (masterKey) { + keyToEncrypt = masterKey.encKey; + + // Only encrypt the master password hash if masterKey exists as + // we won't have a masterKeyHash without a masterKey + const masterKeyHash = await this.stateService.getKeyHash(); + if (masterKeyHash != null) { + encryptedMasterKeyHash = await this.cryptoService.rsaEncrypt( + Utils.fromUtf8ToArray(masterKeyHash), + pubKey, + ); + } + } else { + const userKey = await this.cryptoService.getUserKey(); + keyToEncrypt = userKey.key; + } + + const encryptedKey = await this.cryptoService.rsaEncrypt(keyToEncrypt, pubKey); + + const request = new PasswordlessAuthRequest( + encryptedKey.encryptedString, + encryptedMasterKeyHash?.encryptedString, + await this.appIdService.getAppId(), + requestApproved, + ); + return await this.apiService.putAuthRequest(id, request); + } + + private saveState( + strategy: + | UserApiLoginStrategy + | PasswordLoginStrategy + | SsoLoginStrategy + | AuthRequestLoginStrategy + | WebAuthnLoginStrategy, + ) { + this.logInStrategy = strategy; + this.startSessionTimeout(); + } + + private clearState() { + this.logInStrategy = null; + this.clearSessionTimeout(); + } + + private startSessionTimeout() { + this.clearSessionTimeout(); + this.sessionTimeout = setTimeout(() => this.clearState(), sessionTimeoutLength); + } + + private clearSessionTimeout() { + if (this.sessionTimeout != null) { + clearTimeout(this.sessionTimeout); + } + } +} diff --git a/libs/common/src/auth/abstractions/auth.service.ts b/libs/common/src/auth/abstractions/auth.service.ts index 896a0d02775..dc51e2fdb0f 100644 --- a/libs/common/src/auth/abstractions/auth.service.ts +++ b/libs/common/src/auth/abstractions/auth.service.ts @@ -1,50 +1,6 @@ -import { Observable } from "rxjs"; - -import { AuthRequestPushNotification } from "../../models/response/notification.response"; -import { MasterKey } from "../../types/key"; import { AuthenticationStatus } from "../enums/authentication-status"; -import { AuthResult } from "../models/domain/auth-result"; -import { - UserApiLoginCredentials, - PasswordLoginCredentials, - SsoLoginCredentials, - AuthRequestLoginCredentials, - WebAuthnLoginCredentials, -} from "../models/domain/login-credentials"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { AuthRequestResponse } from "../models/response/auth-request.response"; export abstract class AuthService { - masterPasswordHash: string; - email: string; - accessCode: string; - authRequestId: string; - ssoEmail2FaSessionToken: string; - - logIn: ( - credentials: - | UserApiLoginCredentials - | PasswordLoginCredentials - | SsoLoginCredentials - | AuthRequestLoginCredentials - | WebAuthnLoginCredentials, - ) => Promise; - logInTwoFactor: ( - twoFactor: TokenTwoFactorRequest, - captchaResponse: string, - ) => Promise; - logOut: (callback: () => void) => void; - makePreloginKey: (masterPassword: string, email: string) => Promise; - authingWithUserApiKey: () => boolean; - authingWithSso: () => boolean; - authingWithPassword: () => boolean; - authingWithPasswordless: () => boolean; getAuthStatus: (userId?: string) => Promise; - authResponsePushNotification: (notification: AuthRequestPushNotification) => Promise; - passwordlessLogin: ( - id: string, - key: string, - requestApproved: boolean, - ) => Promise; - getPushNotificationObs$: () => Observable; + logOut: (callback: () => void) => void; } diff --git a/libs/common/src/auth/services/anonymous-hub.service.ts b/libs/common/src/auth/services/anonymous-hub.service.ts index 594b52806c4..4d5e060531e 100644 --- a/libs/common/src/auth/services/anonymous-hub.service.ts +++ b/libs/common/src/auth/services/anonymous-hub.service.ts @@ -6,6 +6,7 @@ import { } from "@microsoft/signalr"; import { MessagePackHubProtocol } from "@microsoft/signalr-protocol-msgpack"; +import { LoginStrategyServiceAbstraction } from "../../../../auth/src/common/abstractions/login-strategy.service"; import { AuthRequestPushNotification, NotificationResponse, @@ -13,7 +14,6 @@ import { import { EnvironmentService } from "../../platform/abstractions/environment.service"; import { LogService } from "../../platform/abstractions/log.service"; import { AnonymousHubService as AnonymousHubServiceAbstraction } from "../abstractions/anonymous-hub.service"; -import { AuthService } from "../abstractions/auth.service"; export class AnonymousHubService implements AnonymousHubServiceAbstraction { private anonHubConnection: HubConnection; @@ -21,7 +21,7 @@ export class AnonymousHubService implements AnonymousHubServiceAbstraction { constructor( private environmentService: EnvironmentService, - private authService: AuthService, + private loginStrategyService: LoginStrategyServiceAbstraction, private logService: LogService, ) {} @@ -54,7 +54,7 @@ export class AnonymousHubService implements AnonymousHubServiceAbstraction { } private async ProcessNotification(notification: NotificationResponse) { - await this.authService.authResponsePushNotification( + await this.loginStrategyService.authResponsePushNotification( notification.payload as AuthRequestPushNotification, ); } diff --git a/libs/common/src/auth/services/auth.service.ts b/libs/common/src/auth/services/auth.service.ts index 29ea3eeece6..14d49956a43 100644 --- a/libs/common/src/auth/services/auth.service.ts +++ b/libs/common/src/auth/services/auth.service.ts @@ -1,269 +1,19 @@ -import { Observable, Subject } from "rxjs"; - import { ApiService } from "../../abstractions/api.service"; -import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; -import { PreloginRequest } from "../../models/request/prelogin.request"; -import { ErrorResponse } from "../../models/response/error.response"; -import { AuthRequestPushNotification } from "../../models/response/notification.response"; -import { AppIdService } from "../../platform/abstractions/app-id.service"; import { CryptoService } from "../../platform/abstractions/crypto.service"; -import { EncryptService } from "../../platform/abstractions/encrypt.service"; -import { EnvironmentService } from "../../platform/abstractions/environment.service"; -import { I18nService } from "../../platform/abstractions/i18n.service"; -import { LogService } from "../../platform/abstractions/log.service"; import { MessagingService } from "../../platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "../../platform/abstractions/platform-utils.service"; import { StateService } from "../../platform/abstractions/state.service"; -import { KdfType, KeySuffixOptions } from "../../platform/enums"; -import { Utils } from "../../platform/misc/utils"; -import { PasswordStrengthServiceAbstraction } from "../../tools/password-strength"; -import { MasterKey } from "../../types/key"; -import { AuthRequestCryptoServiceAbstraction } from "../abstractions/auth-request-crypto.service.abstraction"; +import { KeySuffixOptions } from "../../platform/enums"; import { AuthService as AuthServiceAbstraction } from "../abstractions/auth.service"; -import { DeviceTrustCryptoServiceAbstraction } from "../abstractions/device-trust-crypto.service.abstraction"; -import { KeyConnectorService } from "../abstractions/key-connector.service"; -import { TokenService } from "../abstractions/token.service"; -import { TwoFactorService } from "../abstractions/two-factor.service"; import { AuthenticationStatus } from "../enums/authentication-status"; -import { AuthenticationType } from "../enums/authentication-type"; -import { AuthRequestLoginStrategy } from "../login-strategies/auth-request-login.strategy"; -import { PasswordLoginStrategy } from "../login-strategies/password-login.strategy"; -import { SsoLoginStrategy } from "../login-strategies/sso-login.strategy"; -import { UserApiLoginStrategy } from "../login-strategies/user-api-login.strategy"; -import { WebAuthnLoginStrategy } from "../login-strategies/webauthn-login.strategy"; -import { AuthResult } from "../models/domain/auth-result"; -import { KdfConfig } from "../models/domain/kdf-config"; -import { - AuthRequestLoginCredentials, - PasswordLoginCredentials, - SsoLoginCredentials, - UserApiLoginCredentials, - WebAuthnLoginCredentials, -} from "../models/domain/login-credentials"; -import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request"; -import { PasswordlessAuthRequest } from "../models/request/passwordless-auth.request"; -import { AuthRequestResponse } from "../models/response/auth-request.response"; - -const sessionTimeoutLength = 2 * 60 * 1000; // 2 minutes export class AuthService implements AuthServiceAbstraction { - get email(): string { - if ( - this.logInStrategy instanceof PasswordLoginStrategy || - this.logInStrategy instanceof AuthRequestLoginStrategy || - this.logInStrategy instanceof SsoLoginStrategy - ) { - return this.logInStrategy.email; - } - - return null; - } - - get masterPasswordHash(): string { - return this.logInStrategy instanceof PasswordLoginStrategy - ? this.logInStrategy.masterPasswordHash - : null; - } - - get accessCode(): string { - return this.logInStrategy instanceof AuthRequestLoginStrategy - ? this.logInStrategy.accessCode - : null; - } - - get authRequestId(): string { - return this.logInStrategy instanceof AuthRequestLoginStrategy - ? this.logInStrategy.authRequestId - : null; - } - - get ssoEmail2FaSessionToken(): string { - return this.logInStrategy instanceof SsoLoginStrategy - ? this.logInStrategy.ssoEmail2FaSessionToken - : null; - } - - private logInStrategy: - | UserApiLoginStrategy - | PasswordLoginStrategy - | SsoLoginStrategy - | AuthRequestLoginStrategy - | WebAuthnLoginStrategy; - private sessionTimeout: any; - - private pushNotificationSubject = new Subject(); - constructor( + protected messagingService: MessagingService, protected cryptoService: CryptoService, protected apiService: ApiService, - protected tokenService: TokenService, - protected appIdService: AppIdService, - protected platformUtilsService: PlatformUtilsService, - protected messagingService: MessagingService, - protected logService: LogService, - protected keyConnectorService: KeyConnectorService, - protected environmentService: EnvironmentService, protected stateService: StateService, - protected twoFactorService: TwoFactorService, - protected i18nService: I18nService, - protected encryptService: EncryptService, - protected passwordStrengthService: PasswordStrengthServiceAbstraction, - protected policyService: PolicyService, - protected deviceTrustCryptoService: DeviceTrustCryptoServiceAbstraction, - protected authReqCryptoService: AuthRequestCryptoServiceAbstraction, ) {} - async logIn( - credentials: - | UserApiLoginCredentials - | PasswordLoginCredentials - | SsoLoginCredentials - | AuthRequestLoginCredentials - | WebAuthnLoginCredentials, - ): Promise { - this.clearState(); - - let strategy: - | UserApiLoginStrategy - | PasswordLoginStrategy - | SsoLoginStrategy - | AuthRequestLoginStrategy - | WebAuthnLoginStrategy; - - switch (credentials.type) { - case AuthenticationType.Password: - strategy = new PasswordLoginStrategy( - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.passwordStrengthService, - this.policyService, - this, - ); - break; - case AuthenticationType.Sso: - strategy = new SsoLoginStrategy( - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.keyConnectorService, - this.deviceTrustCryptoService, - this.authReqCryptoService, - this.i18nService, - ); - break; - case AuthenticationType.UserApi: - strategy = new UserApiLoginStrategy( - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.environmentService, - this.keyConnectorService, - ); - break; - case AuthenticationType.AuthRequest: - strategy = new AuthRequestLoginStrategy( - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.deviceTrustCryptoService, - ); - break; - case AuthenticationType.WebAuthn: - strategy = new WebAuthnLoginStrategy( - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - ); - break; - } - - // Note: Do not set the credentials object directly on the strategy. They are - // created in the popup and can cause DeadObject references on Firefox. - const result = await strategy.logIn(credentials as any); - - if (result?.requiresTwoFactor) { - this.saveState(strategy); - } - return result; - } - - async logInTwoFactor( - twoFactor: TokenTwoFactorRequest, - captchaResponse: string, - ): Promise { - if (this.logInStrategy == null) { - throw new Error(this.i18nService.t("sessionTimeout")); - } - - try { - const result = await this.logInStrategy.logInTwoFactor(twoFactor, captchaResponse); - - // Only clear state if 2FA token has been accepted, otherwise we need to be able to try again - if (!result.requiresTwoFactor && !result.requiresCaptcha) { - this.clearState(); - } - return result; - } catch (e) { - // API exceptions are okay, but if there are any unhandled client-side errors then clear state to be safe - if (!(e instanceof ErrorResponse)) { - this.clearState(); - } - throw e; - } - } - - logOut(callback: () => void) { - callback(); - this.messagingService.send("loggedOut"); - } - - authingWithUserApiKey(): boolean { - return this.logInStrategy instanceof UserApiLoginStrategy; - } - - authingWithSso(): boolean { - return this.logInStrategy instanceof SsoLoginStrategy; - } - - authingWithPassword(): boolean { - return this.logInStrategy instanceof PasswordLoginStrategy; - } - - authingWithPasswordless(): boolean { - return this.logInStrategy instanceof AuthRequestLoginStrategy; - } - async getAuthStatus(userId?: string): Promise { // If we don't have an access token or userId, we're logged out const isAuthenticated = await this.stateService.getIsAuthenticated({ userId: userId }); @@ -298,100 +48,8 @@ export class AuthService implements AuthServiceAbstraction { return AuthenticationStatus.Unlocked; } - async makePreloginKey(masterPassword: string, email: string): Promise { - email = email.trim().toLowerCase(); - let kdf: KdfType = null; - let kdfConfig: KdfConfig = null; - try { - const preloginResponse = await this.apiService.postPrelogin(new PreloginRequest(email)); - if (preloginResponse != null) { - kdf = preloginResponse.kdf; - kdfConfig = new KdfConfig( - preloginResponse.kdfIterations, - preloginResponse.kdfMemory, - preloginResponse.kdfParallelism, - ); - } - } catch (e) { - if (e == null || e.statusCode !== 404) { - throw e; - } - } - return await this.cryptoService.makeMasterKey(masterPassword, email, kdf, kdfConfig); - } - - async authResponsePushNotification(notification: AuthRequestPushNotification): Promise { - this.pushNotificationSubject.next(notification.id); - } - - getPushNotificationObs$(): Observable { - return this.pushNotificationSubject.asObservable(); - } - - async passwordlessLogin( - id: string, - key: string, - requestApproved: boolean, - ): Promise { - const pubKey = Utils.fromB64ToArray(key); - - const masterKey = await this.cryptoService.getMasterKey(); - let keyToEncrypt; - let encryptedMasterKeyHash = null; - - if (masterKey) { - keyToEncrypt = masterKey.encKey; - - // Only encrypt the master password hash if masterKey exists as - // we won't have a masterKeyHash without a masterKey - const masterKeyHash = await this.stateService.getKeyHash(); - if (masterKeyHash != null) { - encryptedMasterKeyHash = await this.cryptoService.rsaEncrypt( - Utils.fromUtf8ToArray(masterKeyHash), - pubKey, - ); - } - } else { - const userKey = await this.cryptoService.getUserKey(); - keyToEncrypt = userKey.key; - } - - const encryptedKey = await this.cryptoService.rsaEncrypt(keyToEncrypt, pubKey); - - const request = new PasswordlessAuthRequest( - encryptedKey.encryptedString, - encryptedMasterKeyHash?.encryptedString, - await this.appIdService.getAppId(), - requestApproved, - ); - return await this.apiService.putAuthRequest(id, request); - } - - private saveState( - strategy: - | UserApiLoginStrategy - | PasswordLoginStrategy - | SsoLoginStrategy - | AuthRequestLoginStrategy - | WebAuthnLoginStrategy, - ) { - this.logInStrategy = strategy; - this.startSessionTimeout(); - } - - private clearState() { - this.logInStrategy = null; - this.clearSessionTimeout(); - } - - private startSessionTimeout() { - this.clearSessionTimeout(); - this.sessionTimeout = setTimeout(() => this.clearState(), sessionTimeoutLength); - } - - private clearSessionTimeout() { - if (this.sessionTimeout != null) { - clearTimeout(this.sessionTimeout); - } + logOut(callback: () => void) { + callback(); + this.messagingService.send("loggedOut"); } } diff --git a/libs/common/src/auth/services/webauthn-login/webauthn-login.service.spec.ts b/libs/common/src/auth/services/webauthn-login/webauthn-login.service.spec.ts index 70048d38f77..6cac8358e35 100644 --- a/libs/common/src/auth/services/webauthn-login/webauthn-login.service.spec.ts +++ b/libs/common/src/auth/services/webauthn-login/webauthn-login.service.spec.ts @@ -1,16 +1,16 @@ import { mock } from "jest-mock-extended"; import { firstValueFrom, of } from "rxjs"; +import { LoginStrategyServiceAbstraction, WebAuthnLoginCredentials } from "@bitwarden/auth/common"; + import { ConfigServiceAbstraction } from "../../../platform/abstractions/config/config.service.abstraction"; import { LogService } from "../../../platform/abstractions/log.service"; import { Utils } from "../../../platform/misc/utils"; import { SymmetricCryptoKey } from "../../../platform/models/domain/symmetric-crypto-key"; import { PrfKey } from "../../../types/key"; -import { AuthService } from "../../abstractions/auth.service"; import { WebAuthnLoginApiServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-api.service.abstraction"; import { WebAuthnLoginPrfCryptoServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction"; import { AuthResult } from "../../models/domain/auth-result"; -import { WebAuthnLoginCredentials } from "../../models/domain/login-credentials"; import { WebAuthnLoginCredentialAssertionOptionsView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion-options.view"; import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion.view"; @@ -22,7 +22,7 @@ describe("WebAuthnLoginService", () => { let webAuthnLoginService: WebAuthnLoginService; const webAuthnLoginApiService = mock(); - const authService = mock(); + const loginStrategyService = mock(); const configService = mock(); const webAuthnLoginPrfCryptoService = mock(); const navigatorCredentials = mock(); @@ -75,7 +75,7 @@ describe("WebAuthnLoginService", () => { configService.getFeatureFlag$.mockReturnValue(of(config.featureEnabled)); return new WebAuthnLoginService( webAuthnLoginApiService, - authService, + loginStrategyService, configService, webAuthnLoginPrfCryptoService, window, @@ -273,7 +273,7 @@ describe("WebAuthnLoginService", () => { const assertion = buildWebAuthnLoginCredentialAssertionView(); const mockAuthResult: AuthResult = new AuthResult(); - jest.spyOn(authService, "logIn").mockResolvedValue(mockAuthResult); + jest.spyOn(loginStrategyService, "logIn").mockResolvedValue(mockAuthResult); // Act const result = await webAuthnLoginService.logIn(assertion); @@ -281,7 +281,7 @@ describe("WebAuthnLoginService", () => { // Assert expect(result).toEqual(mockAuthResult); - const callArguments = authService.logIn.mock.calls[0]; + const callArguments = loginStrategyService.logIn.mock.calls[0]; expect(callArguments[0]).toBeInstanceOf(WebAuthnLoginCredentials); }); }); diff --git a/libs/common/src/auth/services/webauthn-login/webauthn-login.service.ts b/libs/common/src/auth/services/webauthn-login/webauthn-login.service.ts index df68bc34081..8c33076b3ef 100644 --- a/libs/common/src/auth/services/webauthn-login/webauthn-login.service.ts +++ b/libs/common/src/auth/services/webauthn-login/webauthn-login.service.ts @@ -1,15 +1,15 @@ import { Observable } from "rxjs"; +import { LoginStrategyServiceAbstraction, WebAuthnLoginCredentials } from "@bitwarden/auth/common"; + import { FeatureFlag } from "../../../enums/feature-flag.enum"; import { ConfigServiceAbstraction } from "../../../platform/abstractions/config/config.service.abstraction"; import { LogService } from "../../../platform/abstractions/log.service"; import { PrfKey } from "../../../types/key"; -import { AuthService } from "../../abstractions/auth.service"; import { WebAuthnLoginApiServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-api.service.abstraction"; import { WebAuthnLoginPrfCryptoServiceAbstraction } from "../../abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction"; import { WebAuthnLoginServiceAbstraction } from "../../abstractions/webauthn/webauthn-login.service.abstraction"; import { AuthResult } from "../../models/domain/auth-result"; -import { WebAuthnLoginCredentials } from "../../models/domain/login-credentials"; import { WebAuthnLoginCredentialAssertionOptionsView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion-options.view"; import { WebAuthnLoginCredentialAssertionView } from "../../models/view/webauthn-login/webauthn-login-credential-assertion.view"; @@ -22,7 +22,7 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction { constructor( private webAuthnLoginApiService: WebAuthnLoginApiServiceAbstraction, - private authService: AuthService, + private loginStrategyService: LoginStrategyServiceAbstraction, private configService: ConfigServiceAbstraction, private webAuthnLoginPrfCryptoService: WebAuthnLoginPrfCryptoServiceAbstraction, private window: Window, @@ -86,7 +86,7 @@ export class WebAuthnLoginService implements WebAuthnLoginServiceAbstraction { assertion.deviceResponse, assertion.prfKey, ); - const result = await this.authService.logIn(credential); + const result = await this.loginStrategyService.logIn(credential); return result; } }