diff --git a/libs/angular/src/auth/guards/redirect.guard.ts b/libs/angular/src/auth/guards/redirect.guard.ts index 0c43673c34..760558dfb5 100644 --- a/libs/angular/src/auth/guards/redirect.guard.ts +++ b/libs/angular/src/auth/guards/redirect.guard.ts @@ -6,6 +6,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; export interface RedirectRoutes { loggedIn: string; @@ -32,6 +33,7 @@ export function redirectGuard(overrides: Partial = {}): CanActiv const authService = inject(AuthService); const cryptoService = inject(CryptoService); const deviceTrustService = inject(DeviceTrustServiceAbstraction); + const logService = inject(LogService); const router = inject(Router); const authStatus = await authService.getAuthStatus(); @@ -49,6 +51,12 @@ export function redirectGuard(overrides: Partial = {}): CanActiv const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$); const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$); if (authStatus === AuthenticationStatus.Locked && tdeEnabled && !everHadUserKey) { + logService.info( + "Sending user to TDE decryption options. AuthStatus is %s. TDE support is %s. Ever had user key is %s.", + AuthenticationStatus[authStatus], + tdeEnabled, + everHadUserKey, + ); return router.createUrlTree([routes.notDecrypted], { queryParams: route.queryParams }); } diff --git a/libs/angular/src/auth/guards/tde-decryption-required.guard.ts b/libs/angular/src/auth/guards/tde-decryption-required.guard.ts index 524ce7dce5..51d1a5a3b5 100644 --- a/libs/angular/src/auth/guards/tde-decryption-required.guard.ts +++ b/libs/angular/src/auth/guards/tde-decryption-required.guard.ts @@ -11,6 +11,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; /** * Only allow access to this route if the vault is locked and has never been decrypted. @@ -23,15 +24,30 @@ export function tdeDecryptionRequiredGuard(): CanActivateFn { const authService = inject(AuthService); const cryptoService = inject(CryptoService); const deviceTrustService = inject(DeviceTrustServiceAbstraction); + const logService = inject(LogService); const router = inject(Router); const authStatus = await authService.getAuthStatus(); const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$); const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$); + + // We need to determine if we should bypass the decryption options and send the user to the vault. + // The ONLY time that we want to send a user to the decryption options is when: + // 1. The user's auth status is Locked, AND + // 2. TDE is enabled, AND + // 3. The user has never had a user key in state since last logout. + // The inverse of this is when we should send the user to the vault. if (authStatus !== AuthenticationStatus.Locked || !tdeEnabled || everHadUserKey) { return router.createUrlTree(["/"]); } + logService.info( + "Sending user to TDE decryption options. AuthStatus is %s. TDE support is %s. Ever had user key is %s.", + AuthenticationStatus[authStatus], + tdeEnabled, + everHadUserKey, + ); + return true; }; } diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index b7ed8906e7..2ba0f682b5 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -87,12 +87,16 @@ export class SsoLoginStrategy extends LoginStrategy { data.userEnteredEmail = credentials.email; + const deviceRequest = await this.buildDeviceRequest(); + + this.logService.info("Logging in with appId %s.", deviceRequest.identifier); + data.tokenRequest = new SsoTokenRequest( credentials.code, credentials.codeVerifier, credentials.redirectUrl, await this.buildTwoFactor(credentials.twoFactor, credentials.email), - await this.buildDeviceRequest(), + deviceRequest, ); this.cache.next(data); @@ -195,12 +199,18 @@ export class SsoLoginStrategy extends LoginStrategy { // Note: TDE and key connector are mutually exclusive if (userDecryptionOptions?.trustedDeviceOption) { + this.logService.info("Attempting to set user key with approved admin auth request."); + + // Try to use the user key from an approved admin request if it exists. + // Using it will clear it from state and future requests will use the device key. await this.trySetUserKeyWithApprovedAdminRequestIfExists(userId); const hasUserKey = await this.cryptoService.hasUserKey(userId); - // Only try to set user key with device key if admin approval request was not successful + // Only try to set user key with device key if admin approval request was not successful. if (!hasUserKey) { + this.logService.info("Attempting to set user key with device key."); + await this.trySetUserKeyWithDeviceKey(tokenResponse, userId); } } else if ( @@ -275,11 +285,27 @@ export class SsoLoginStrategy extends LoginStrategy { ): Promise { const trustedDeviceOption = tokenResponse.userDecryptionOptions?.trustedDeviceOption; + if (!trustedDeviceOption) { + this.logService.error("Unable to set user key due to missing trustedDeviceOption."); + return; + } + const deviceKey = await this.deviceTrustService.getDeviceKey(userId); const encDevicePrivateKey = trustedDeviceOption?.encryptedPrivateKey; const encUserKey = trustedDeviceOption?.encryptedUserKey; if (!deviceKey || !encDevicePrivateKey || !encUserKey) { + if (!deviceKey) { + await this.logService.warning("Unable to set user key due to missing device key."); + } + if (!encDevicePrivateKey) { + await this.logService.warning( + "Unable to set user key due to missing encrypted device private key.", + ); + } + if (!encUserKey) { + await this.logService.warning("Unable to set user key due to missing encrypted user key."); + } return; }