Skip to content

Commit

Permalink
[SM-896] When org is disabled disable the logic and show warning symb…
Browse files Browse the repository at this point in the history
…ols (#6225)

* When org is disabled disable the logic and show warning symbols

* fixing org enabled logic

* removing unused code

* Adding route gaurd logic and new org suspended page

* fixing lint issue

* fixing issues

* Requested changes

* adding back code that was accidentally removed from organization-switcher

* Update bitwarden_license/bit-web/src/app/secrets-manager/shared/org-suspended.component.ts

Co-authored-by: Thomas Avery <[email protected]>

* Removing unused code and updating storybook to set enabled:true

* removing onDestroy

* Will's suggestions

* will's suggested change

* fix nav-item color in story

* Thomas Rittson's suggested changes

* adding back removed spaces

* Adding back white space

* updating guard

* Update bitwarden_license/bit-web/src/app/secrets-manager/guards/sm-org-enabled.guard.ts

Co-authored-by: Thomas Rittson <[email protected]>

* removing ununsed data

* Updating incorrect messages

---------

Co-authored-by: Thomas Avery <[email protected]>
Co-authored-by: William Martin <[email protected]>
Co-authored-by: Thomas Rittson <[email protected]>
  • Loading branch information
4 people authored Oct 16, 2023
1 parent 2dc94ed commit c3856ce
Show file tree
Hide file tree
Showing 26 changed files with 242 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ export class ProductSwitcherContentComponent {
map(([orgs, paramMap]) => {
const routeOrg = orgs.find((o) => o.id === paramMap.get("organizationId"));
// If the active route org doesn't have access to SM, find the first org that does.
const smOrg = routeOrg?.canAccessSecretsManager
? routeOrg
: orgs.find((o) => o.canAccessSecretsManager);
const smOrg =
routeOrg?.canAccessSecretsManager && routeOrg?.enabled == true
? routeOrg
: orgs.find((o) => o.canAccessSecretsManager && o.enabled == true);

/**
* We can update this to the "satisfies" type upon upgrading to TypeScript 4.9
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,5 +131,5 @@ OrgWithoutSecretsManager.args = {

export const OrgWithSecretsManager = Template.bind({});
OrgWithSecretsManager.args = {
mockOrgs: [{ id: "b", canAccessSecretsManager: true }],
mockOrgs: [{ id: "b", canAccessSecretsManager: true, enabled: true }],
};
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 @@ -3638,6 +3638,18 @@
"organizationIsDisabled": {
"message": "Organization suspended"
},
"secretsAccessSuspended": {
"message": "Suspended organizations cannot be accessed. Please contact your organization owner for assistance."
},
"secretsCannotCreate": {
"message": "Secrets cannot be created in suspended organizations. Please contact your organization owner for assistance."
},
"projectsCannotCreate": {
"message": "Projects cannot be created in suspended organizations. Please contact your organization owner for assistance."
},
"serviceAccountsCannotCreate": {
"message": "Service accounts cannot be created in suspended organizations. Please contact your organization owner for assistance."
},
"disabledOrganizationFilterError": {
"message": "Items in suspended organizations cannot be accessed. Contact your organization owner for assistance."
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { inject } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivateFn, createUrlTreeFromSnapshot } from "@angular/router";

import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";

/**
* Redirects from root `/sm` to first organization with access to SM
*/
export const organizationEnabledGuard: CanActivateFn = async (route: ActivatedRouteSnapshot) => {
const syncService = inject(SyncService);
const orgService = inject(OrganizationService);

/** Workaround to avoid service initialization race condition. */
if ((await syncService.getLastSync()) == null) {
await syncService.fullSync(false);
}

const org = orgService.get(route.params.organizationId);
if (org == null || !org.canAccessSecretsManager) {
return createUrlTreeFromSnapshot(route, ["/"]);
}

if (!org.enabled) {
return createUrlTreeFromSnapshot(route, ["/sm", org.id, "organization-suspended"]);
}

return true;
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
[(open)]="open"
[exactMatch]="true"
>
<i
slot="end"
*ngIf="!activeOrganization.enabled"
class="bwi bwi-exclamation-triangle tw-my-auto !tw-text-danger"
></i>
<ng-container *ngIf="organizations$ | async as organizations">
<bit-nav-item
*ngFor="let org of organizations"
Expand All @@ -16,6 +21,11 @@
(mainContentClicked)="toggle()"
[hideActiveStyles]="true"
>
<i
slot="end"
*ngIf="org.enabled == false"
class="bwi bwi-exclamation-triangle !tw-text-danger"
></i>
</bit-nav-item>
</ng-container>
<bit-nav-item
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ import type { Organization } from "@bitwarden/common/admin-console/models/domain
export class OrgSwitcherComponent {
protected organizations$: Observable<Organization[]> =
this.organizationService.organizations$.pipe(
map((orgs) => orgs.filter(this.filter).sort((a, b) => a.name.localeCompare(b.name)))
map((orgs) =>
orgs
.filter((org) => this.filter(org))
.sort((a, b) => a.name.localeCompare(b.name))
.sort((a, b) => (a.enabled ? -1 : 1))
)
);

protected activeOrganization$: Observable<Organization> = combineLatest([
this.route.paramMap,
this.organizations$,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
protected userIsAdmin: boolean;
protected showOnboarding = false;
protected loading = true;
protected organizationEnabled = false;

protected view$: Observable<{
allProjects: ProjectListView[];
Expand Down Expand Up @@ -107,6 +108,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
this.organizationName = org.name;
this.userIsAdmin = org.isAdmin;
this.loading = true;
this.organizationEnabled = org.enabled;
});

const projects$ = combineLatest([
Expand Down Expand Up @@ -208,6 +210,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Edit,
organizationEnabled: this.organizationEnabled,
projectId: projectId,
},
});
Expand All @@ -218,6 +221,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Add,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand All @@ -227,6 +231,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Add,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand All @@ -246,6 +251,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Add,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand All @@ -256,6 +262,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
organizationId: this.organizationId,
operation: OperationType.Edit,
secretId: secretId,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand All @@ -273,6 +280,7 @@ export class OverviewComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Add,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export enum OperationType {
export interface ProjectOperation {
organizationId: string;
operation: OperationType;
organizationEnabled: boolean;
projectId?: string;
}

Expand Down Expand Up @@ -63,6 +64,15 @@ export class ProjectDialogComponent implements OnInit {
}

submit = async () => {
if (!this.data.organizationEnabled) {
this.platformUtilsService.showToast(
"error",
null,
this.i18nService.t("projectsCannotCreate")
);
return;
}

this.formGroup.markAllAsTouched();

if (this.formGroup.invalid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { combineLatest, combineLatestWith, filter, Observable, startWith, switchMap } from "rxjs";

import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
Expand Down Expand Up @@ -31,14 +32,16 @@ export class ProjectSecretsComponent {
private organizationId: string;
private projectId: string;
protected project$: Observable<ProjectView>;
private organizationEnabled: boolean;

constructor(
private route: ActivatedRoute,
private projectService: ProjectService,
private secretService: SecretService,
private dialogService: DialogService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService
private i18nService: I18nService,
private organizationService: OrganizationService
) {}

ngOnInit() {
Expand All @@ -60,6 +63,7 @@ export class ProjectSecretsComponent {
switchMap(async ([_, params]) => {
this.organizationId = params.organizationId;
this.projectId = params.projectId;
this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled;
return await this.getSecretsByProject();
})
);
Expand All @@ -75,6 +79,7 @@ export class ProjectSecretsComponent {
organizationId: this.organizationId,
operation: OperationType.Edit,
secretId: secretId,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand All @@ -93,6 +98,7 @@ export class ProjectSecretsComponent {
organizationId: this.organizationId,
operation: OperationType.Add,
projectId: this.projectId,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
takeUntil,
} from "rxjs";

import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
Expand All @@ -33,7 +34,7 @@ export class ProjectComponent implements OnInit, OnDestroy {

private organizationId: string;
private projectId: string;

private organizationEnabled: boolean;
private destroy$ = new Subject<void>();

constructor(
Expand All @@ -42,7 +43,8 @@ export class ProjectComponent implements OnInit, OnDestroy {
private router: Router,
private dialogService: DialogService,
private platformUtilsService: PlatformUtilsService,
private i18nService: I18nService
private i18nService: I18nService,
private organizationService: OrganizationService
) {}

ngOnInit(): void {
Expand All @@ -69,6 +71,7 @@ export class ProjectComponent implements OnInit, OnDestroy {
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
this.organizationId = params.organizationId;
this.projectId = params.projectId;
this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled;
});
}

Expand All @@ -82,6 +85,7 @@ export class ProjectComponent implements OnInit, OnDestroy {
data: {
organizationId: this.organizationId,
operation: OperationType.Edit,
organizationEnabled: this.organizationEnabled,
projectId: this.projectId,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, OnInit } from "@angular/core";
import { ActivatedRoute } from "@angular/router";
import { combineLatest, lastValueFrom, Observable, startWith, switchMap } from "rxjs";

import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { DialogService } from "@bitwarden/components";

import { ProjectListView } from "../../models/view/project-list.view";
Expand Down Expand Up @@ -32,12 +33,14 @@ export class ProjectsComponent implements OnInit {
protected search: string;

private organizationId: string;
private organizationEnabled: boolean;

constructor(
private route: ActivatedRoute,
private projectService: ProjectService,
private accessPolicyService: AccessPolicyService,
private dialogService: DialogService
private dialogService: DialogService,
private organizationService: OrganizationService
) {}

ngOnInit() {
Expand All @@ -48,6 +51,8 @@ export class ProjectsComponent implements OnInit {
]).pipe(
switchMap(async ([params]) => {
this.organizationId = params.organizationId;
this.organizationEnabled = this.organizationService.get(params.organizationId)?.enabled;

return await this.getProjects();
})
);
Expand All @@ -62,6 +67,7 @@ export class ProjectsComponent implements OnInit {
data: {
organizationId: this.organizationId,
operation: OperationType.Edit,
organizationEnabled: this.organizationEnabled,
projectId: projectId,
},
});
Expand All @@ -72,6 +78,7 @@ export class ProjectsComponent implements OnInit {
data: {
organizationId: this.organizationId,
operation: OperationType.Add,
organizationEnabled: this.organizationEnabled,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface SecretOperation {
operation: OperationType;
projectId?: string;
secretId?: string;
organizationEnabled: boolean;
}

@Component({
Expand Down Expand Up @@ -163,6 +164,11 @@ export class SecretDialogComponent implements OnInit {
}

submit = async () => {
if (!this.data.organizationEnabled) {
this.platformUtilsService.showToast("error", null, this.i18nService.t("secretsCannotCreate"));
return;
}

this.formGroup.markAllAsTouched();

if (this.formGroup.invalid) {
Expand Down
Loading

0 comments on commit c3856ce

Please sign in to comment.