Skip to content

Commit

Permalink
[PM-10314] Update Warnings for Verifying Domains and Single Org Polic…
Browse files Browse the repository at this point in the history
…y Auto Enable (#11688)

* Updated description and warning for single org policy.

* Added check for verified domains in disabling single org.
  • Loading branch information
jrmccannon authored Oct 28, 2024
1 parent f86bc9b commit 53f13f4
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</div>
</ng-container>
<ng-container bitDialogFooter>
<button bitButton buttonType="primary" bitFormButton type="submit">
<button bitButton buttonType="primary" [disabled]="saveDisabled" bitFormButton type="submit">
{{ "save" | i18n }}
</button>
<button bitButton buttonType="secondary" bitDialogClose type="button">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class PolicyEditComponent implements AfterViewInit {
policyType = PolicyType;
loading = true;
enabled = false;
saveDisabled = false;
defaultTypes: any[];
policyComponent: BasePolicyComponent;

Expand Down Expand Up @@ -72,6 +73,8 @@ export class PolicyEditComponent implements AfterViewInit {
this.policyComponent.policy = this.data.policy;
this.policyComponent.policyResponse = this.policyResponse;

this.saveDisabled = !this.policyResponse.canToggleState;

this.cdr.detectChanges();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<bit-callout type="warning">
{{ "singleOrgPolicyWarning" | i18n }}
<bit-callout *ngIf="accountDeprovisioningEnabled$ | async; else disabledBlock" type="warning">
{{ "singleOrgPolicyMemberWarning" | i18n }}
</bit-callout>
<ng-template #disabledBlock>
<bit-callout type="warning">
{{ "singleOrgPolicyWarning" | i18n }}
</bit-callout>
</ng-template>

<bit-form-control>
<input type="checkbox" bitCheckbox [formControl]="enabled" id="enabled" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component } from "@angular/core";
import { Component, OnInit } from "@angular/core";
import { firstValueFrom, Observable } from "rxjs";

import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { PolicyRequest } from "@bitwarden/common/admin-console/models/request/policy.request";
Expand All @@ -19,14 +20,31 @@ export class SingleOrgPolicy extends BasePolicy {
selector: "policy-single-org",
templateUrl: "single-org.component.html",
})
export class SingleOrgPolicyComponent extends BasePolicyComponent {
export class SingleOrgPolicyComponent extends BasePolicyComponent implements OnInit {
constructor(
private i18nService: I18nService,
private configService: ConfigService,
) {
super();
}

protected accountDeprovisioningEnabled$: Observable<boolean> = this.configService.getFeatureFlag$(
FeatureFlag.AccountDeprovisioning,
);

async ngOnInit() {
super.ngOnInit();

const isAccountDeprovisioningEnabled = await firstValueFrom(this.accountDeprovisioningEnabled$);
this.policy.description = isAccountDeprovisioningEnabled
? "singleOrgPolicyDesc"
: "singleOrgDesc";

if (!this.policyResponse.canToggleState) {
this.enabled.disable();
}
}

async buildRequest(policiesEnabledMap: Map<PolicyType, boolean>): Promise<PolicyRequest> {
if (await this.configService.getFeatureFlag(FeatureFlag.Pm13322AddPolicyDefinitions)) {
// We are now relying on server-side validation only
Expand All @@ -48,6 +66,15 @@ export class SingleOrgPolicyComponent extends BasePolicyComponent {
),
);
}

if (
(await firstValueFrom(this.accountDeprovisioningEnabled$)) &&
!this.policyResponse.canToggleState
) {
throw new Error(
this.i18nService.t("disableRequiredError", this.i18nService.t("singleOrg")),
);
}
}

return super.buildRequest(policiesEnabledMap);
Expand Down
12 changes: 12 additions & 0 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -4684,12 +4684,18 @@
"singleOrgDesc": {
"message": "Restrict members from joining other organizations."
},
"singleOrgPolicyDesc": {
"message": "Restrict members from joining other organizations. This policy is required for organizations that have enabled domain verification."
},
"singleOrgBlockCreateMessage": {
"message": "Your current organization has a policy that does not allow you to join more than one organization. Please contact your organization admins or sign up from a different Bitwarden account."
},
"singleOrgPolicyWarning": {
"message": "Organization members who are not owners or admins and are already a member of another organization will be removed from your organization."
},
"singleOrgPolicyMemberWarning": {
"message": "Non-compliant members will be placed in revoked status until they leave all other organizations. Administrators are exempt and can restore members once compliance is met."
},
"requireSso": {
"message": "Require single sign-on authentication"
},
Expand Down Expand Up @@ -9531,5 +9537,11 @@
},
"selfHostingTitleProper": {
"message": "Self-Hosting"
},
"verified-domain-single-org-warning" : {
"message": "Verifying a domain will turn on the single organization policy."
},
"single-org-revoked-user-warning": {
"message": "Non-compliant members will be revoked. Administrators can restore members once they leave all other organizations."
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import { ActivatedRoute, Params } from "@angular/router";
import { concatMap, Observable, Subject, take, takeUntil } from "rxjs";
import {
concatMap,
firstValueFrom,
map,
Observable,
Subject,
take,
takeUntil,
withLatestFrom,
} from "rxjs";

import { OrgDomainApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain-api.service.abstraction";
import { OrgDomainServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization-domain/org-domain.service.abstraction";
import { OrganizationDomainResponse } from "@bitwarden/common/admin-console/abstractions/organization-domain/responses/organization-domain.response";
import { HttpStatusCode } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { DialogService, ToastService } from "@bitwarden/components";

Expand All @@ -31,13 +41,13 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {

constructor(
private route: ActivatedRoute,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService,
private orgDomainApiService: OrgDomainApiServiceAbstraction,
private orgDomainService: OrgDomainServiceAbstraction,
private dialogService: DialogService,
private validationService: ValidationService,
private toastService: ToastService,
private configService: ConfigService,
) {}

// eslint-disable-next-line @typescript-eslint/no-empty-function
Expand All @@ -64,13 +74,38 @@ export class DomainVerificationComponent implements OnInit, OnDestroy {
this.loading = false;
}

addDomain() {
async addDomain() {
const domainAddEditDialogData: DomainAddEditDialogData = {
organizationId: this.organizationId,
orgDomain: null,
existingDomainNames: this.getExistingDomainNames(),
};

await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning).pipe(
withLatestFrom(this.orgDomains$),
map(async ([accountDeprovisioningEnabled, organizationDomains]) => {
if (
accountDeprovisioningEnabled &&
organizationDomains.every((domain) => domain.verifiedDate === null)
) {
await this.dialogService.openSimpleDialog({
title: { key: "verified-domain-single-org-warning" },
content: { key: "single-org-revoked-user-warning" },
cancelButtonText: { key: "cancel" },
acceptButtonText: { key: "confirm" },
acceptAction: () => this.openAddDomainDialog(domainAddEditDialogData),
type: "info",
});
} else {
await this.openAddDomainDialog(domainAddEditDialogData);
}
}),
),
);
}

private async openAddDomainDialog(domainAddEditDialogData: DomainAddEditDialogData) {
this.dialogService.open(DomainAddEditDialogComponent, {
data: domainAddEditDialogData,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class PolicyResponse extends BaseResponse {
type: PolicyType;
data: any;
enabled: boolean;
canToggleState: boolean;

constructor(response: any) {
super(response);
Expand All @@ -16,5 +17,6 @@ export class PolicyResponse extends BaseResponse {
this.type = this.getResponseProperty("Type");
this.data = this.getResponseProperty("Data");
this.enabled = this.getResponseProperty("Enabled");
this.canToggleState = this.getResponseProperty("CanToggleState") ?? true;
}
}

0 comments on commit 53f13f4

Please sign in to comment.