From 0224b2b981f21d151534305912b505d71e279212 Mon Sep 17 00:00:00 2001 From: Maciej Zieniuk Date: Mon, 7 Apr 2025 15:50:41 +0100 Subject: [PATCH] confirm key connector domain page showing correctly --- apps/web/src/locales/en/messages.json | 3 + .../src/auth/components/sso.component.ts | 4 +- libs/auth/src/angular/sso/sso.component.ts | 29 +++++ ...onfirm-key-connector-domain.component.html | 33 +++++- .../confirm-key-connector-domain.component.ts | 108 +++++++++++++----- 5 files changed, 146 insertions(+), 31 deletions(-) diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index cedd3fc3596..a3dc4ac455a 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -10567,5 +10567,8 @@ }, "cannotCreateCollection": { "message": "Free organizations may have up to 2 collections. Upgrade to a paid plan to add more collections." + }, + "confirmKeyConnectorDomain": { + "message": "Confirm Key Connector domain" } } diff --git a/libs/angular/src/auth/components/sso.component.ts b/libs/angular/src/auth/components/sso.component.ts index 8c19e1d7e11..da3fc0c550b 100644 --- a/libs/angular/src/auth/components/sso.component.ts +++ b/libs/angular/src/auth/components/sso.component.ts @@ -222,6 +222,7 @@ export class SsoComponent implements OnInit { } if (authResult.requiresKeyConnectorDomainConfirmation != null) { + this.logService.debug("Key Connector domain confirmation required"); return await this.handleKeyConnectorDomainConfirmation( authResult.requiresKeyConnectorDomainConfirmation, authResult.userId, @@ -436,11 +437,12 @@ export class SsoComponent implements OnInit { kdfMemory?: number; kdfParallelism?: number; keyConnectorUrl: string; + organizationId: string; }, userId: UserId, ) { await this.router.navigate(["confirm-key-connector-domain"], { - state: { + queryParams: { ...request, userId, }, diff --git a/libs/auth/src/angular/sso/sso.component.ts b/libs/auth/src/angular/sso/sso.component.ts index 5d3fd689dd6..af1cb0f0428 100644 --- a/libs/auth/src/angular/sso/sso.component.ts +++ b/libs/auth/src/angular/sso/sso.component.ts @@ -36,6 +36,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { UserId } from "@bitwarden/common/types/guid"; import { AsyncActionsModule, ButtonModule, @@ -46,6 +47,7 @@ import { ToastService, } from "@bitwarden/components"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy"; +import { KdfType } from "@bitwarden/key-management"; import { SsoClientType, SsoComponentService } from "./sso-component.service"; @@ -433,6 +435,14 @@ export class SsoComponent implements OnInit { return await this.handleTwoFactorRequired(orgSsoIdentifier); } + if (authResult.requiresKeyConnectorDomainConfirmation != null) { + this.logService.warning("Key Connector domain confirmation required"); + return await this.handleKeyConnectorDomainConfirmation( + authResult.requiresKeyConnectorDomainConfirmation, + authResult.userId, + ); + } + // Everything after the 2FA check is considered a successful login // Just have to figure out where to send the user await this.loginSuccessHandlerService.run(authResult.userId); @@ -638,4 +648,23 @@ export class SsoComponent implements OnInit { this.identifierFormControl.setValue(storedIdentifier); } } + + private async handleKeyConnectorDomainConfirmation( + request: { + kdf: KdfType; + kdfIterations: number; + kdfMemory?: number; + kdfParallelism?: number; + keyConnectorUrl: string; + organizationId: string; + }, + userId: UserId, + ) { + await this.router.navigate(["confirm-key-connector-domain"], { + queryParams: { + ...request, + userId, + }, + }); + } } diff --git a/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.html b/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.html index 7c89b545c5a..902df06cc0f 100644 --- a/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.html +++ b/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.html @@ -1 +1,32 @@ -
+@if (loading) { +
+ +
+} @else { +
+

{{ "confirmKeyConnectorDomain" | i18n }}.

+

{{ "keyConnectorDomain" | i18n }}:

+

{{ keyConnectorUrl }}

+ + + +
+} diff --git a/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.ts b/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.ts index ef244015986..ac1cadbe4a5 100644 --- a/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.ts +++ b/libs/key-management-ui/src/key-connector/confirm-key-connector-domain.component.ts @@ -1,18 +1,14 @@ import { CommonModule } from "@angular/common"; -import { Component, OnDestroy, OnInit } from "@angular/core"; -import { ReactiveFormsModule } from "@angular/forms"; -import { ActivatedRoute, Router } from "@angular/router"; -import { Subject } from "rxjs"; +import { Component, OnInit } from "@angular/core"; +import { ActivatedRoute, Router, RouterModule } from "@angular/router"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { KeyConnectorService } from "@bitwarden/common/key-management/key-connector/abstractions/key-connector.service"; -import { - AsyncActionsModule, - ButtonModule, - FormFieldModule, - IconButtonModule, -} from "@bitwarden/components"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; +import { UserId } from "@bitwarden/common/types/guid"; +import { AsyncActionsModule, ButtonModule, IconButtonModule } from "@bitwarden/components"; +import { KdfType } from "@bitwarden/key-management"; @Component({ selector: "confirm-key-connector-domain", @@ -21,38 +17,92 @@ import { imports: [ CommonModule, JslibModule, - ReactiveFormsModule, ButtonModule, - FormFieldModule, AsyncActionsModule, IconButtonModule, + RouterModule, ], }) -export class ConfirmKeyConnectorDomainComponent implements OnInit, OnDestroy { - private destroy$ = new Subject(); +export class ConfirmKeyConnectorDomainComponent implements OnInit { + protected loading = true; + protected keyConnectorUrl!: string; + private userId!: UserId; + private organizationId!: string; + private kdf!: KdfType; + private kdfIterations!: number; + private kdfMemory?: number; + private kdfParallelism?: number; constructor( private route: ActivatedRoute, private router: Router, - private accountService: AccountService, + private logService: LogService, private keyConnectorService: KeyConnectorService, - ) { - // TODO - // this.accountService.activeAccount$.pipe(takeUntil(this.destroy$)).subscribe((account) => { - // console.log("[confirm-key-connector-domain]: account", account); - // }); - } + private messagingService: MessagingService, + ) {} - ngOnInit() { - throw new Error("Method not implemented."); - } + async ngOnInit() { + const userId = this.route.snapshot.queryParamMap.get("userId") as UserId | null; + const organizationId = this.route.snapshot.queryParamMap.get("organizationId"); + const keyConnectorUrl = this.route.snapshot.queryParamMap.get("keyConnectorUrl"); + const kdf = Number.parseInt(this.route.snapshot.queryParamMap.get("kdf") ?? ""); + const kdfIterations = Number.parseInt( + this.route.snapshot.queryParamMap.get("kdfIterations") ?? "", + ); + const kdfMemory = Number.parseInt(this.route.snapshot.queryParamMap.get("kdfMemory") ?? ""); + const kdfParallelism = Number.parseInt( + this.route.snapshot.queryParamMap.get("kdfParallelism") ?? "", + ); - ngOnDestroy() { - this.destroy$.next(); - this.destroy$.complete(); + this.logService.info( + "[confirm-key-connector-domain] userId %s, organizationId %s, keyConnectorUrl %s, kdf %s, kdfIterations %s, kdfMemory %s, kdfParallelism %s", + userId, + organizationId, + keyConnectorUrl, + KdfType[kdf], + kdfIterations, + kdfMemory, + kdfParallelism, + ); + + if ( + userId == null || + organizationId == null || + keyConnectorUrl == null || + Number.isNaN(kdf) || + !kdfIterations + ) { + this.logService.info("[confirm-key-connector-domain] missing required parameters"); + this.messagingService.send("logout"); + return; + } + + this.keyConnectorUrl = keyConnectorUrl; + this.userId = userId; + this.organizationId = organizationId; + this.kdf = kdf; + this.kdfIterations = kdfIterations; + this.kdfMemory = kdfMemory ? kdfMemory : undefined; + this.kdfParallelism = kdfParallelism ? kdfParallelism : undefined; + + this.loading = false; } confirm = async () => { - // this.keyConnectorService.convertNewSsoUserToKeyConnector(); + await this.keyConnectorService.convertNewSsoUserToKeyConnector( + this.organizationId, + this.userId, + this.keyConnectorUrl, + this.kdf, + this.kdfIterations, + this.kdfMemory, + this.kdfParallelism, + ); + + this.messagingService.send("loggedIn"); + }; + + cancel = async () => { + this.messagingService.send("logout"); }; }