diff --git a/apps/web/src/app/organizations/billing/organization-billing.module.ts b/apps/web/src/app/organizations/billing/organization-billing.module.ts
index 71222e3ba5f..17d825fbae7 100644
--- a/apps/web/src/app/organizations/billing/organization-billing.module.ts
+++ b/apps/web/src/app/organizations/billing/organization-billing.module.ts
@@ -11,6 +11,7 @@ import { OrganizationBillingRoutingModule } from "./organization-billing-routing
import { OrganizationBillingTabComponent } from "./organization-billing-tab.component";
import { OrganizationSubscriptionCloudComponent } from "./organization-subscription-cloud.component";
import { OrganizationSubscriptionSelfhostComponent } from "./organization-subscription-selfhost.component";
+import { SecretsManagerEnrollComponent } from "./secrets-manager/enroll.component";
import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
@NgModule({
@@ -25,6 +26,7 @@ import { SubscriptionHiddenComponent } from "./subscription-hidden.component";
OrganizationSubscriptionSelfhostComponent,
OrganizationSubscriptionCloudComponent,
SubscriptionHiddenComponent,
+ SecretsManagerEnrollComponent,
],
})
export class OrganizationBillingModule {}
diff --git a/apps/web/src/app/organizations/billing/organization-subscription-cloud.component.html b/apps/web/src/app/organizations/billing/organization-subscription-cloud.component.html
index 25dc12dc2fb..3e7fda5cafc 100644
--- a/apps/web/src/app/organizations/billing/organization-subscription-cloud.component.html
+++ b/apps/web/src/app/organizations/billing/organization-subscription-cloud.component.html
@@ -108,6 +108,13 @@
*ngIf="showChangePlan"
>
+
+
+
{{ subscriptionDesc }}
i.sponsoredSubscriptionItem);
}
diff --git a/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.html b/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.html
new file mode 100644
index 00000000000..56a48e09fe7
--- /dev/null
+++ b/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.html
@@ -0,0 +1,13 @@
+
diff --git a/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.ts b/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.ts
new file mode 100644
index 00000000000..e28e089a3a9
--- /dev/null
+++ b/apps/web/src/app/organizations/billing/secrets-manager/enroll.component.ts
@@ -0,0 +1,52 @@
+import { Component, Input, OnInit } from "@angular/core";
+import { FormBuilder } from "@angular/forms";
+
+import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
+import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction";
+import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
+import { OrganizationEnrollSecretsManagerRequest } from "@bitwarden/common/models/request/organization/organization-enroll-secrets-manager.request";
+import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
+
+import { flagEnabled } from "../../../../utils/flags";
+
+@Component({
+ selector: "sm-enroll",
+ templateUrl: "enroll.component.html",
+})
+export class SecretsManagerEnrollComponent implements OnInit {
+ @Input() enabled: boolean;
+ @Input() organizationId: string;
+
+ protected formGroup = this.formBuilder.group({
+ enabled: [false],
+ });
+
+ protected showSecretsManager = false;
+
+ constructor(
+ private formBuilder: FormBuilder,
+ private organizationApiService: OrganizationApiServiceAbstraction,
+ private platformUtilsService: PlatformUtilsService,
+ private i18nService: I18nService,
+ private syncService: SyncService
+ ) {
+ this.showSecretsManager = flagEnabled("secretsManager");
+ }
+
+ ngOnInit(): void {
+ this.formGroup.setValue({
+ enabled: this.enabled,
+ });
+ }
+
+ protected submit = async () => {
+ this.formGroup.markAllAsTouched();
+
+ const request = new OrganizationEnrollSecretsManagerRequest();
+ request.enabled = this.formGroup.value.enabled;
+
+ await this.organizationApiService.updateEnrollSecretsManager(this.organizationId, request);
+ await this.syncService.fullSync(true);
+ this.platformUtilsService.showToast("success", null, this.i18nService.t("subscriptionUpdated"));
+ };
+}
diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json
index 06025f869d0..de2f1119f2a 100644
--- a/apps/web/src/locales/en/messages.json
+++ b/apps/web/src/locales/en/messages.json
@@ -6475,5 +6475,11 @@
},
"selectionIsRequired": {
"message": "Selection is required."
+ },
+ "secretsManagerSubscriptionDesc": {
+ "message": "Turn on organization access to the Secrets Manager at no charge during the Beta program. Users can be granted access to the Beta in Members."
+ },
+ "secretsManagerEnable": {
+ "message": "Enable Secrets Manager Beta"
}
}
diff --git a/libs/common/src/abstractions/organization/organization-api.service.abstraction.ts b/libs/common/src/abstractions/organization/organization-api.service.abstraction.ts
index 6fe56db2269..f3aec0a72e8 100644
--- a/libs/common/src/abstractions/organization/organization-api.service.abstraction.ts
+++ b/libs/common/src/abstractions/organization/organization-api.service.abstraction.ts
@@ -11,6 +11,7 @@ import { OrganizationSubscriptionUpdateRequest } from "../../models/request/orga
import { OrganizationTaxInfoUpdateRequest } from "../../models/request/organization-tax-info-update.request";
import { OrganizationUpdateRequest } from "../../models/request/organization-update.request";
import { OrganizationUpgradeRequest } from "../../models/request/organization-upgrade.request";
+import { OrganizationEnrollSecretsManagerRequest } from "../../models/request/organization/organization-enroll-secrets-manager.request";
import { PaymentRequest } from "../../models/request/payment.request";
import { SeatRequest } from "../../models/request/seat.request";
import { StorageRequest } from "../../models/request/storage.request";
@@ -59,4 +60,8 @@ export class OrganizationApiServiceAbstraction {
getSso: (id: string) => Promise;
updateSso: (id: string, request: OrganizationSsoRequest) => Promise;
selfHostedSyncLicense: (id: string) => Promise;
+ updateEnrollSecretsManager: (
+ id: string,
+ request: OrganizationEnrollSecretsManagerRequest
+ ) => Promise;
}
diff --git a/libs/common/src/models/request/organization/organization-enroll-secrets-manager.request.ts b/libs/common/src/models/request/organization/organization-enroll-secrets-manager.request.ts
new file mode 100644
index 00000000000..a213b07bba7
--- /dev/null
+++ b/libs/common/src/models/request/organization/organization-enroll-secrets-manager.request.ts
@@ -0,0 +1,3 @@
+export class OrganizationEnrollSecretsManagerRequest {
+ enabled: boolean;
+}
diff --git a/libs/common/src/models/response/organization.response.ts b/libs/common/src/models/response/organization.response.ts
index ce684e34521..9f7649646df 100644
--- a/libs/common/src/models/response/organization.response.ts
+++ b/libs/common/src/models/response/organization.response.ts
@@ -26,6 +26,7 @@ export class OrganizationResponse extends BaseResponse {
use2fa: boolean;
useApi: boolean;
useResetPassword: boolean;
+ useSecretsManager: boolean;
hasPublicAndPrivateKeys: boolean;
constructor(response: any) {
@@ -53,6 +54,7 @@ export class OrganizationResponse extends BaseResponse {
this.use2fa = this.getResponseProperty("Use2fa");
this.useApi = this.getResponseProperty("UseApi");
this.useResetPassword = this.getResponseProperty("UseResetPassword");
+ this.useSecretsManager = this.getResponseProperty("UseSecretsManager");
this.hasPublicAndPrivateKeys = this.getResponseProperty("HasPublicAndPrivateKeys");
}
}
diff --git a/libs/common/src/services/organization/organization-api.service.ts b/libs/common/src/services/organization/organization-api.service.ts
index 1b86511a045..b5c02e7b08d 100644
--- a/libs/common/src/services/organization/organization-api.service.ts
+++ b/libs/common/src/services/organization/organization-api.service.ts
@@ -13,6 +13,7 @@ import { OrganizationSubscriptionUpdateRequest } from "../../models/request/orga
import { OrganizationTaxInfoUpdateRequest } from "../../models/request/organization-tax-info-update.request";
import { OrganizationUpdateRequest } from "../../models/request/organization-update.request";
import { OrganizationUpgradeRequest } from "../../models/request/organization-upgrade.request";
+import { OrganizationEnrollSecretsManagerRequest } from "../../models/request/organization/organization-enroll-secrets-manager.request";
import { PaymentRequest } from "../../models/request/payment.request";
import { SeatRequest } from "../../models/request/seat.request";
import { StorageRequest } from "../../models/request/storage.request";
@@ -292,4 +293,14 @@ export class OrganizationApiService implements OrganizationApiServiceAbstraction
false
);
}
+
+ async updateEnrollSecretsManager(id: string, request: OrganizationEnrollSecretsManagerRequest) {
+ await this.apiService.send(
+ "POST",
+ "/organizations/" + id + "/enroll-secrets-manager",
+ request,
+ true,
+ true
+ );
+ }
}