fix duo subscriptions and org vs individual duo setup (#9859)
This commit is contained in:
parent
ed9d82ef1e
commit
a5e7fde413
|
@ -1,7 +1,8 @@
|
|||
import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, takeUntil, map, lastValueFrom } from "rxjs";
|
||||
import { tap } from "rxjs/operators";
|
||||
import { first, tap } from "rxjs/operators";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
|
@ -64,6 +65,9 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
|
|||
}
|
||||
|
||||
async manage(type: TwoFactorProviderType) {
|
||||
// clear any existing subscriptions before creating a new one
|
||||
this.twoFactorSetupSubscription?.unsubscribe();
|
||||
|
||||
switch (type) {
|
||||
case TwoFactorProviderType.OrganizationDuo: {
|
||||
const twoFactorVerifyDialogRef = TwoFactorVerifyComponent.open(this.dialogService, {
|
||||
|
@ -75,9 +79,18 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent {
|
|||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const duoComp = TwoFactorDuoComponent.open(this.dialogService, { data: result });
|
||||
const enabled: boolean = await lastValueFrom(duoComp.closed);
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Duo);
|
||||
const duoComp: DialogRef<boolean, any> = TwoFactorDuoComponent.open(this.dialogService, {
|
||||
data: {
|
||||
authResponse: result,
|
||||
organizationId: this.organizationId,
|
||||
},
|
||||
});
|
||||
this.twoFactorSetupSubscription = duoComp.componentInstance.onChangeStatus
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
duoComp.close();
|
||||
this.updateStatus(enabled, TwoFactorProviderType.OrganizationDuo);
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export class TwoFactorDuoComponent extends TwoFactorBaseComponent {
|
|||
override componentName = "app-two-factor-duo";
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) protected data: AuthResponse<TwoFactorDuoResponse>,
|
||||
@Inject(DIALOG_DATA) protected data: TwoFactorDuoComponentConfig,
|
||||
apiService: ApiService,
|
||||
i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService,
|
||||
|
@ -71,8 +71,17 @@ export class TwoFactorDuoComponent extends TwoFactorBaseComponent {
|
|||
}
|
||||
|
||||
async ngOnInit() {
|
||||
super.auth(this.data);
|
||||
this.processResponse(this.data.response);
|
||||
if (!this.data?.authResponse) {
|
||||
throw Error("TwoFactorDuoComponent requires a TwoFactorDuoResponse to initialize");
|
||||
}
|
||||
|
||||
super.auth(this.data.authResponse);
|
||||
this.processResponse(this.data.authResponse.response);
|
||||
|
||||
if (this.data.organizationId) {
|
||||
this.type = TwoFactorProviderType.OrganizationDuo;
|
||||
this.organizationId = this.data.organizationId;
|
||||
}
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
|
@ -124,8 +133,13 @@ export class TwoFactorDuoComponent extends TwoFactorBaseComponent {
|
|||
*/
|
||||
static open = (
|
||||
dialogService: DialogService,
|
||||
config: DialogConfig<AuthResponse<TwoFactorDuoResponse>>,
|
||||
config: DialogConfig<TwoFactorDuoComponentConfig>,
|
||||
) => {
|
||||
return dialogService.open<boolean>(TwoFactorDuoComponent, config);
|
||||
};
|
||||
}
|
||||
|
||||
type TwoFactorDuoComponentConfig = {
|
||||
authResponse: AuthResponse<TwoFactorDuoResponse>;
|
||||
organizationId?: string;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, OnDestroy, OnInit, Type, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { firstValueFrom, lastValueFrom, Observable, Subject, takeUntil } from "rxjs";
|
||||
import {
|
||||
first,
|
||||
firstValueFrom,
|
||||
lastValueFrom,
|
||||
Observable,
|
||||
Subject,
|
||||
Subscription,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
|
||||
import { ModalRef } from "@bitwarden/angular/components/modal/modal.ref";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
|
@ -36,9 +44,6 @@ import { TwoFactorYubiKeyComponent } from "./two-factor-yubikey.component";
|
|||
export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
||||
@ViewChild("yubikeyTemplate", { read: ViewContainerRef, static: true })
|
||||
yubikeyModalRef: ViewContainerRef;
|
||||
@ViewChild("duoTemplate", { read: ViewContainerRef, static: true }) duoModalRef: ViewContainerRef;
|
||||
@ViewChild("emailTemplate", { read: ViewContainerRef, static: true })
|
||||
emailModalRef: ViewContainerRef;
|
||||
|
||||
organizationId: string;
|
||||
organization: Organization;
|
||||
|
@ -53,6 +58,7 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
|
||||
protected destroy$ = new Subject<void>();
|
||||
private twoFactorAuthPolicyAppliesToActiveUser: boolean;
|
||||
protected twoFactorSetupSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
protected dialogService: DialogService,
|
||||
|
@ -126,6 +132,9 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
async manage(type: TwoFactorProviderType) {
|
||||
// clear any existing subscriptions before creating a new one
|
||||
this.twoFactorSetupSubscription?.unsubscribe();
|
||||
|
||||
switch (type) {
|
||||
case TwoFactorProviderType.Authenticator: {
|
||||
const result: AuthResponse<TwoFactorAuthenticatorResponse> =
|
||||
|
@ -137,9 +146,12 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
this.dialogService,
|
||||
{ data: result },
|
||||
);
|
||||
authComp.componentInstance.onChangeStatus.subscribe((enabled: boolean) => {
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Authenticator);
|
||||
});
|
||||
this.twoFactorSetupSubscription = authComp.componentInstance.onChangeStatus
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
authComp.close();
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Authenticator);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case TwoFactorProviderType.Yubikey: {
|
||||
|
@ -150,9 +162,11 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
const yubiComp = await this.openModal(this.yubikeyModalRef, TwoFactorYubiKeyComponent);
|
||||
yubiComp.auth(result);
|
||||
yubiComp.onUpdated.pipe(takeUntil(this.destroy$)).subscribe((enabled: boolean) => {
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Yubikey);
|
||||
});
|
||||
this.twoFactorSetupSubscription = yubiComp.onUpdated
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Yubikey);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case TwoFactorProviderType.Duo: {
|
||||
|
@ -162,11 +176,16 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
return;
|
||||
}
|
||||
const duoComp: DialogRef<boolean, any> = TwoFactorDuoComponent.open(this.dialogService, {
|
||||
data: result,
|
||||
});
|
||||
duoComp.componentInstance.onChangeStatus.subscribe((enabled: boolean) => {
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Duo);
|
||||
data: {
|
||||
authResponse: result,
|
||||
},
|
||||
});
|
||||
this.twoFactorSetupSubscription = duoComp.componentInstance.onChangeStatus
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
duoComp.close();
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Duo);
|
||||
});
|
||||
break;
|
||||
}
|
||||
case TwoFactorProviderType.Email: {
|
||||
|
@ -175,12 +194,16 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
if (!result) {
|
||||
return;
|
||||
}
|
||||
const authComp: DialogRef<boolean, any> = TwoFactorEmailComponent.open(this.dialogService, {
|
||||
data: result,
|
||||
});
|
||||
authComp.componentInstance.onChangeStatus
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
const emailComp: DialogRef<boolean, any> = TwoFactorEmailComponent.open(
|
||||
this.dialogService,
|
||||
{
|
||||
data: result,
|
||||
},
|
||||
);
|
||||
this.twoFactorSetupSubscription = emailComp.componentInstance.onChangeStatus
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
emailComp.close();
|
||||
this.updateStatus(enabled, TwoFactorProviderType.Email);
|
||||
});
|
||||
break;
|
||||
|
@ -195,9 +218,12 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
|||
this.dialogService,
|
||||
{ data: result },
|
||||
);
|
||||
webAuthnComp.componentInstance.onChangeStatus.subscribe((enabled: boolean) => {
|
||||
this.updateStatus(enabled, TwoFactorProviderType.WebAuthn);
|
||||
});
|
||||
this.twoFactorSetupSubscription = webAuthnComp.componentInstance.onChangeStatus
|
||||
.pipe(first(), takeUntil(this.destroy$))
|
||||
.subscribe((enabled: boolean) => {
|
||||
webAuthnComp.close();
|
||||
this.updateStatus(enabled, TwoFactorProviderType.WebAuthn);
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
Loading…
Reference in New Issue