diff --git a/libs/angular/src/auth/components/sso.component.spec.ts b/libs/angular/src/auth/components/sso.component.spec.ts index 8b89031e731..0db2daa3702 100644 --- a/libs/angular/src/auth/components/sso.component.spec.ts +++ b/libs/angular/src/auth/components/sso.component.spec.ts @@ -1,14 +1,14 @@ import { Component } from "@angular/core"; import { ComponentFixture, TestBed } from "@angular/core/testing"; import { ActivatedRoute, Router } from "@angular/router"; -import { MockProxy, mock } from "jest-mock-extended"; +import { mock, MockProxy } from "jest-mock-extended"; import { BehaviorSubject, Observable, of } from "rxjs"; import { FakeKeyConnectorUserDecryptionOption as KeyConnectorUserDecryptionOption, - LoginStrategyServiceAbstraction, FakeTrustedDeviceUserDecryptionOption as TrustedDeviceUserDecryptionOption, FakeUserDecryptionOptions as UserDecryptionOptions, + LoginStrategyServiceAbstraction, UserDecryptionOptionsServiceAbstraction, } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; @@ -30,8 +30,10 @@ import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/sp import { UserId } from "@bitwarden/common/types/guid"; import { ToastService } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; +import { KdfType } from "@bitwarden/key-management"; import { SsoComponent } from "./sso.component"; + // test component that extends the SsoComponent @Component({}) class TestSsoComponent extends SsoComponent {} @@ -298,6 +300,41 @@ describe("SsoComponent", () => { }); }); + describe("Key Connector scenarios", () => { + it("navigates to the confirm key connector domain route when the auth result requires key connector domain confirmation", async () => { + const authResult = new AuthResult(); + authResult.userId = userId; + authResult.requiresKeyConnectorDomainConfirmation = { + organizationId: orgIdFromState, + keyConnectorUrl: "https://key-connector-url.bitwarden.com", + kdf: KdfType.Argon2id, + kdfIterations: 10, + kdfMemory: 64, + kdfParallelism: 4, + }; + + mockLoginStrategyService.logIn.mockResolvedValue(authResult); + + await _component.logIn(code, codeVerifier, orgIdFromState); + expect(mockLoginStrategyService.logIn).toHaveBeenCalledTimes(1); + + expect(mockRouter.navigate).toHaveBeenCalledTimes(1); + expect(mockRouter.navigate).toHaveBeenCalledWith(["confirm-key-connector-domain"], { + queryParams: { + organizationId: orgIdFromState, + keyConnectorUrl: "https://key-connector-url.bitwarden.com", + kdf: KdfType.Argon2id, + kdfIterations: 10, + kdfMemory: 64, + kdfParallelism: 4, + userId: userId, + }, + }); + + expect(mockLogService.error).not.toHaveBeenCalled(); + }); + }); + // Shared test helpers const testChangePasswordOnSuccessfulLogin = () => { it("navigates to the component's defined change password route when onSuccessfulLoginChangePasswordNavigate callback is undefined", async () => { diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index 546fa0c5fa7..8fa00584d60 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -30,8 +30,8 @@ import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/sym import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { UserId } from "@bitwarden/common/types/guid"; -import { DeviceKey, UserKey, MasterKey } from "@bitwarden/common/types/key"; -import { KdfConfigService, KeyService } from "@bitwarden/key-management"; +import { DeviceKey, MasterKey, UserKey } from "@bitwarden/common/types/key"; +import { KdfConfigService, KdfType, KeyService } from "@bitwarden/key-management"; import { AuthRequestServiceAbstraction, @@ -475,16 +475,23 @@ describe("SsoLoginStrategy", () => { it("converts new SSO user with no master password to Key Connector on first login", async () => { tokenResponse.key = null; + tokenResponse.kdf = KdfType.Argon2id; + tokenResponse.kdfIterations = 10; + tokenResponse.kdfMemory = 64; + tokenResponse.kdfParallelism = 4; apiService.postIdentityToken.mockResolvedValue(tokenResponse); - await ssoLoginStrategy.logIn(credentials); + const result = await ssoLoginStrategy.logIn(credentials); - expect(keyConnectorService.convertNewSsoUserToKeyConnector).toHaveBeenCalledWith( - tokenResponse, - ssoOrgId, - userId, - ); + expect(result.requiresKeyConnectorDomainConfirmation).toEqual({ + organizationId: ssoOrgId, + keyConnectorUrl: keyConnectorUrl, + kdf: KdfType.Argon2id, + kdfIterations: 10, + kdfMemory: 64, + kdfParallelism: 4, + }); }); it("decrypts and sets the user key if Key Connector is enabled and the user doesn't have a master password", async () => { @@ -531,16 +538,23 @@ describe("SsoLoginStrategy", () => { it("converts new SSO user with no master password to Key Connector on first login", async () => { tokenResponse.key = null; + tokenResponse.kdf = KdfType.Argon2id; + tokenResponse.kdfIterations = 10; + tokenResponse.kdfMemory = 64; + tokenResponse.kdfParallelism = 4; apiService.postIdentityToken.mockResolvedValue(tokenResponse); - await ssoLoginStrategy.logIn(credentials); + const result = await ssoLoginStrategy.logIn(credentials); - expect(keyConnectorService.convertNewSsoUserToKeyConnector).toHaveBeenCalledWith( - tokenResponse, - ssoOrgId, - userId, - ); + expect(result.requiresKeyConnectorDomainConfirmation).toEqual({ + organizationId: ssoOrgId, + keyConnectorUrl: keyConnectorUrl, + kdf: KdfType.Argon2id, + kdfIterations: 10, + kdfMemory: 64, + kdfParallelism: 4, + }); }); it("decrypts and sets the user key if Key Connector is enabled and the user doesn't have a master password", async () => {