1
0
mirror of https://github.com/bitwarden/browser synced 2026-03-02 11:31:44 +00:00

confirm key connector domain page showing correctly

This commit is contained in:
Maciej Zieniuk
2025-04-07 15:50:41 +01:00
parent 914143207f
commit 0224b2b981
5 changed files with 146 additions and 31 deletions

View File

@@ -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"
}
}

View File

@@ -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,
},

View File

@@ -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,
},
});
}
}

View File

@@ -1 +1,32 @@
<div></div>
@if (loading) {
<div class="tw-absolute tw-flex tw-size-full tw-items-center tw-justify-center">
<i class="bwi bwi-spinner bwi-spin bwi-lg" [attr.aria-label]="'loading' | i18n"></i>
</div>
} @else {
<div>
<p>{{ "confirmKeyConnectorDomain" | i18n }}.</p>
<p class="tw-mb-0">{{ "keyConnectorDomain" | i18n }}:</p>
<p class="tw-text-muted tw-mb-6">{{ keyConnectorUrl }}</p>
<button
bitButton
type="button"
buttonType="primary"
class="tw-w-full tw-mb-2"
[bitAction]="confirm"
[block]="true"
>
{{ "confirm" | i18n }}
</button>
<button
bitButton
type="button"
buttonType="secondary"
class="tw-w-full"
[bitAction]="cancel"
[block]="true"
>
{{ "cancel" | i18n }}
</button>
</div>
}

View File

@@ -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<void>();
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");
};
}