mirror of
https://github.com/bitwarden/browser
synced 2026-01-26 14:23:46 +00:00
Implement organization integrations page with routing and state management
- Added routing for organization integrations including device management, event management, single sign-on, and user provisioning. - Created OrganizationIntegrationsState to manage integrations and organization data. - Introduced OrganizationIntegrationsResolver for preloading organization and integration data. - Updated components to utilize the new state management and resolver. - Refactored integration routes to follow updated naming conventions.
This commit is contained in:
@@ -79,7 +79,7 @@
|
||||
<bit-nav-item
|
||||
icon="bwi-msp"
|
||||
[text]="'integrations' | i18n"
|
||||
route="integrations"
|
||||
route="integrations/single-sign-on"
|
||||
*ngIf="integrationPageEnabled$ | async"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@let integrationsList = integrations$ | async;
|
||||
|
||||
<section class="tw-mb-9">
|
||||
<h2 bitTypography="h2">
|
||||
{{ "deviceManagement" | i18n }}
|
||||
|
||||
@@ -1,13 +1,27 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { IntegrationType } from "@bitwarden/common/enums/integration-type.enum";
|
||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||
|
||||
import { IntegrationGridComponent } from "../integration-grid/integration-grid.component";
|
||||
import { FilterIntegrationsPipe } from "../integrations.pipe";
|
||||
import { OrganizationIntegrationsState } from "../organization-integrations.state";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "device-management",
|
||||
templateUrl: "device-management.component.html",
|
||||
imports: [SharedModule, IntegrationGridComponent, FilterIntegrationsPipe],
|
||||
})
|
||||
export class DeviceManagementComponent implements OnInit {
|
||||
constructor() {}
|
||||
integrations$ = this.state.integrations$;
|
||||
|
||||
constructor(private state: OrganizationIntegrationsState) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get IntegrationType(): typeof IntegrationType {
|
||||
return IntegrationType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@let integrationsList = integrations$ | async;
|
||||
|
||||
<section class="tw-mb-9">
|
||||
<h2 bitTypography="h2">
|
||||
{{ "eventManagement" | i18n }}
|
||||
|
||||
@@ -1,13 +1,26 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { IntegrationType } from "@bitwarden/common/enums/integration-type.enum";
|
||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||
|
||||
import { IntegrationGridComponent } from "../integration-grid/integration-grid.component";
|
||||
import { FilterIntegrationsPipe } from "../integrations.pipe";
|
||||
import { OrganizationIntegrationsState } from "../organization-integrations.state";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "event-management",
|
||||
template: "event-management.component.html",
|
||||
templateUrl: "event-management.component.html",
|
||||
imports: [SharedModule, IntegrationGridComponent, FilterIntegrationsPipe],
|
||||
})
|
||||
export class EventManagementComponent implements OnInit {
|
||||
constructor() {}
|
||||
integrations$ = this.state.integrations$;
|
||||
constructor(private state: OrganizationIntegrationsState) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get IntegrationType(): typeof IntegrationType {
|
||||
return IntegrationType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
@let organization = organization$ | async;
|
||||
|
||||
<app-header>
|
||||
@if (organization) {
|
||||
<bit-tab-nav-bar slot="tabs">
|
||||
<bit-tab-link route="sso">{{ "singleSignOn" | i18n }}</bit-tab-link>
|
||||
<bit-tab-link route="single-sign-on">{{ "singleSignOn" | i18n }}</bit-tab-link>
|
||||
@if (organization?.useScim || organization?.useDirectory) {
|
||||
<bit-tab-link route="provisioning">{{ "userProvisioning" | i18n }}</bit-tab-link>
|
||||
<bit-tab-link route="user-provisioning">{{ "userProvisioning" | i18n }}</bit-tab-link>
|
||||
}
|
||||
@if (organization?.useEvents) {
|
||||
<bit-tab-link route="event-management">{{ "eventManagement" | i18n }}</bit-tab-link>
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, Observable, Subject, switchMap, takeUntil, takeWhile } from "rxjs";
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { Integration } from "@bitwarden/bit-common/dirt/organization-integrations/models/integration";
|
||||
import { OrganizationIntegrationServiceName } from "@bitwarden/bit-common/dirt/organization-integrations/models/organization-integration-service-type";
|
||||
import { OrganizationIntegrationType } from "@bitwarden/bit-common/dirt/organization-integrations/models/organization-integration-type";
|
||||
import { OrganizationIntegrationService } from "@bitwarden/bit-common/dirt/organization-integrations/services/organization-integration-service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { IntegrationType } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { getById } from "@bitwarden/common/platform/misc";
|
||||
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
|
||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||
|
||||
import { IntegrationGridComponent } from "./integration-grid/integration-grid.component";
|
||||
import { FilterIntegrationsPipe } from "./integrations.pipe";
|
||||
import { OrganizationIntegrationsState } from "./organization-integrations.state";
|
||||
|
||||
// attempted, but because bit-tab-group is not OnPush, caused more issues than it solved
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
@@ -26,291 +11,11 @@ import { FilterIntegrationsPipe } from "./integrations.pipe";
|
||||
@Component({
|
||||
selector: "ac-integrations",
|
||||
templateUrl: "./integrations.component.html",
|
||||
imports: [SharedModule, IntegrationGridComponent, HeaderModule, FilterIntegrationsPipe],
|
||||
imports: [SharedModule, HeaderModule],
|
||||
})
|
||||
export class AdminConsoleIntegrationsComponent implements OnInit, OnDestroy {
|
||||
tabIndex: number = 0;
|
||||
organization$: Observable<Organization> = new Observable<Organization>();
|
||||
isEventManagementForDataDogAndCrowdStrikeEnabled: boolean = false;
|
||||
private destroy$ = new Subject<void>();
|
||||
export class AdminConsoleIntegrationsComponent {
|
||||
integrations = this.state.integrations;
|
||||
organization = this.state.organization;
|
||||
|
||||
// initialize the integrations list with default integrations
|
||||
integrationsList: Integration[] = [
|
||||
{
|
||||
name: "AD FS",
|
||||
linkURL: "https://bitwarden.com/help/saml-adfs/",
|
||||
image: "../../../../../../../images/integrations/azure-active-directory.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Auth0",
|
||||
linkURL: "https://bitwarden.com/help/saml-auth0/",
|
||||
image: "../../../../../../../images/integrations/logo-auth0-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "AWS",
|
||||
linkURL: "https://bitwarden.com/help/saml-aws/",
|
||||
image: "../../../../../../../images/integrations/aws-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/aws-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/saml-azure/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Duo",
|
||||
linkURL: "https://bitwarden.com/help/saml-duo/",
|
||||
image: "../../../../../../../images/integrations/logo-duo-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Google",
|
||||
linkURL: "https://bitwarden.com/help/saml-google/",
|
||||
image: "../../../../../../../images/integrations/logo-google-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "JumpCloud",
|
||||
linkURL: "https://bitwarden.com/help/saml-jumpcloud/",
|
||||
image: "../../../../../../../images/integrations/logo-jumpcloud-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/jumpcloud-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "KeyCloak",
|
||||
linkURL: "https://bitwarden.com/help/saml-keycloak/",
|
||||
image: "../../../../../../../images/integrations/logo-keycloak-icon.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/saml-okta/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/saml-onelogin/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "PingFederate",
|
||||
linkURL: "https://bitwarden.com/help/saml-pingfederate/",
|
||||
image: "../../../../../../../images/integrations/logo-ping-identity-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-entra-id-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/okta-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/onelogin-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "JumpCloud",
|
||||
linkURL: "https://bitwarden.com/help/jumpcloud-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-jumpcloud-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/jumpcloud-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Ping Identity",
|
||||
linkURL: "https://bitwarden.com/help/ping-identity-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-ping-identity-badge-color.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Active Directory",
|
||||
linkURL: "https://bitwarden.com/help/ldap-directory/",
|
||||
image: "../../../../../../../images/integrations/azure-active-directory.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-entra-id/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Google Workspace",
|
||||
linkURL: "https://bitwarden.com/help/workspace-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-google-badge-color.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/okta-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/onelogin-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Splunk",
|
||||
linkURL: "https://bitwarden.com/help/splunk-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-splunk-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/splunk-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Sentinel",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-sentinel-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-sentinel-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Rapid7",
|
||||
linkURL: "https://bitwarden.com/help/rapid7-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-rapid7-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/rapid7-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Elastic",
|
||||
linkURL: "https://bitwarden.com/help/elastic-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-elastic-badge-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Panther",
|
||||
linkURL: "https://bitwarden.com/help/panther-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-panther-round-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Sumo Logic",
|
||||
linkURL: "https://bitwarden.com/help/sumo-logic-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-sumo-logic-siem.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/logo-sumo-logic-siem-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
newBadgeExpiration: "2025-12-31",
|
||||
},
|
||||
{
|
||||
name: "Microsoft Intune",
|
||||
linkURL: "https://bitwarden.com/help/deploy-browser-extensions-with-intune/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-intune-color.svg",
|
||||
type: IntegrationType.DEVICE,
|
||||
},
|
||||
];
|
||||
|
||||
async ngOnInit() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
if (!userId) {
|
||||
throw new Error("User ID not found");
|
||||
}
|
||||
|
||||
this.organization$ = this.route.params.pipe(
|
||||
switchMap((params) =>
|
||||
this.organizationService.organizations$(userId).pipe(
|
||||
getById(params.organizationId),
|
||||
// Filter out undefined values
|
||||
takeWhile((org: Organization | undefined) => !!org),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Sets the organization ID which also loads the integrations$
|
||||
this.organization$
|
||||
.pipe(
|
||||
switchMap((org) => this.organizationIntegrationService.setOrganizationId(org.id)),
|
||||
takeUntil(this.destroy$),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
private organizationIntegrationService: OrganizationIntegrationService,
|
||||
) {
|
||||
this.configService
|
||||
.getFeatureFlag$(FeatureFlag.EventManagementForDataDogAndCrowdStrike)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((isEnabled) => {
|
||||
this.isEventManagementForDataDogAndCrowdStrikeEnabled = isEnabled;
|
||||
});
|
||||
|
||||
// Add the new event based items to the list
|
||||
if (this.isEventManagementForDataDogAndCrowdStrikeEnabled) {
|
||||
const crowdstrikeIntegration: Integration = {
|
||||
name: OrganizationIntegrationServiceName.CrowdStrike,
|
||||
linkURL: "https://bitwarden.com/help/crowdstrike-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-crowdstrike-black.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
description: "crowdstrikeEventIntegrationDesc",
|
||||
canSetupConnection: true,
|
||||
integrationType: OrganizationIntegrationType.Hec,
|
||||
};
|
||||
|
||||
this.integrationsList.push(crowdstrikeIntegration);
|
||||
|
||||
const datadogIntegration: Integration = {
|
||||
name: OrganizationIntegrationServiceName.Datadog,
|
||||
linkURL: "https://bitwarden.com/help/datadog-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-datadog-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
description: "datadogEventIntegrationDesc",
|
||||
canSetupConnection: true,
|
||||
integrationType: OrganizationIntegrationType.Datadog,
|
||||
};
|
||||
|
||||
this.integrationsList.push(datadogIntegration);
|
||||
}
|
||||
|
||||
// For all existing event based configurations loop through and assign the
|
||||
// organizationIntegration for the correct services.
|
||||
this.organizationIntegrationService.integrations$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((integrations) => {
|
||||
// reset all event based integrations to null first - in case one was deleted
|
||||
this.integrationsList.forEach((i) => {
|
||||
i.organizationIntegration = null;
|
||||
});
|
||||
|
||||
integrations.forEach((integration) => {
|
||||
const item = this.integrationsList.find((i) => i.name === integration.serviceName);
|
||||
if (item) {
|
||||
item.organizationIntegration = integration;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
// use in the view
|
||||
get IntegrationType(): typeof IntegrationType {
|
||||
return IntegrationType;
|
||||
}
|
||||
constructor(private state: OrganizationIntegrationsState) {}
|
||||
}
|
||||
|
||||
@@ -3,16 +3,29 @@ import { RouterModule, Routes } from "@angular/router";
|
||||
|
||||
import { organizationPermissionsGuard } from "@bitwarden/web-vault/app/admin-console/organizations/guards/org-permissions.guard";
|
||||
|
||||
import { DeviceManagementComponent } from "./device-management/device-management.component";
|
||||
import { EventManagementComponent } from "./event-management/event-management.component";
|
||||
import { AdminConsoleIntegrationsComponent } from "./integrations.component";
|
||||
import { OrganizationIntegrationsResolver } from "./organization-integrations.resolver";
|
||||
import { SingleSignOnComponent } from "./single-sign-on/single-sign-on.component";
|
||||
import { UserProvisioningComponent } from "./user-provisioning/user-provisioning.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: "",
|
||||
canActivate: [organizationPermissionsGuard((org) => org.canAccessIntegrations)],
|
||||
component: AdminConsoleIntegrationsComponent,
|
||||
data: {
|
||||
titleId: "integrations",
|
||||
},
|
||||
component: AdminConsoleIntegrationsComponent,
|
||||
resolve: { integrations: OrganizationIntegrationsResolver },
|
||||
children: [
|
||||
{ path: "", component: AdminConsoleIntegrationsComponent },
|
||||
{ path: "single-sign-on", component: SingleSignOnComponent },
|
||||
{ path: "user-provisioning", component: UserProvisioningComponent },
|
||||
{ path: "event-management", component: EventManagementComponent },
|
||||
{ path: "device-management", component: DeviceManagementComponent },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { DeviceManagementComponent } from "@bitwarden/angular/auth/device-management/device-management.component";
|
||||
import { OrganizationIntegrationApiService } from "@bitwarden/bit-common/dirt/organization-integrations/services/organization-integration-api.service";
|
||||
import { OrganizationIntegrationConfigurationApiService } from "@bitwarden/bit-common/dirt/organization-integrations/services/organization-integration-configuration-api.service";
|
||||
import { OrganizationIntegrationService } from "@bitwarden/bit-common/dirt/organization-integrations/services/organization-integration-service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { safeProvider } from "@bitwarden/ui-common";
|
||||
|
||||
import { EventManagementComponent } from "./event-management/event-management.component";
|
||||
import { AdminConsoleIntegrationsComponent } from "./integrations.component";
|
||||
import { OrganizationIntegrationsRoutingModule } from "./organization-integrations-routing.module";
|
||||
import { OrganizationIntegrationsResolver } from "./organization-integrations.resolver";
|
||||
import { SingleSignOnComponent } from "./single-sign-on/single-sign-on.component";
|
||||
import { UserProvisioningComponent } from "./user-provisioning/user-provisioning.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [AdminConsoleIntegrationsComponent, OrganizationIntegrationsRoutingModule],
|
||||
imports: [
|
||||
AdminConsoleIntegrationsComponent,
|
||||
OrganizationIntegrationsRoutingModule,
|
||||
SingleSignOnComponent,
|
||||
UserProvisioningComponent,
|
||||
DeviceManagementComponent,
|
||||
EventManagementComponent,
|
||||
],
|
||||
providers: [
|
||||
safeProvider({
|
||||
provide: OrganizationIntegrationService,
|
||||
@@ -27,6 +39,7 @@ import { OrganizationIntegrationsRoutingModule } from "./organization-integratio
|
||||
useClass: OrganizationIntegrationConfigurationApiService,
|
||||
deps: [ApiService],
|
||||
}),
|
||||
OrganizationIntegrationsResolver,
|
||||
],
|
||||
})
|
||||
export class OrganizationIntegrationsModule {}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ActivatedRouteSnapshot, Resolve } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { take, takeWhile } from "rxjs/operators";
|
||||
|
||||
import { Integration } from "@bitwarden/bit-common/dirt/organization-integrations/models/integration";
|
||||
import { OrganizationIntegrationServiceName } from "@bitwarden/bit-common/dirt/organization-integrations/models/organization-integration-service-type";
|
||||
import { OrganizationIntegrationType } from "@bitwarden/bit-common/dirt/organization-integrations/models/organization-integration-type";
|
||||
import { OrganizationIntegrationService } from "@bitwarden/bit-common/dirt/organization-integrations/services/organization-integration-service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { IntegrationType } from "@bitwarden/common/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { getById } from "@bitwarden/common/platform/misc";
|
||||
|
||||
import { OrganizationIntegrationsState } from "./organization-integrations.state";
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationIntegrationsResolver implements Resolve<boolean> {
|
||||
constructor(
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
private organizationIntegrationService: OrganizationIntegrationService,
|
||||
private state: OrganizationIntegrationsState,
|
||||
) {}
|
||||
|
||||
async resolve(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("User ID not found");
|
||||
}
|
||||
|
||||
const orgId = route.paramMap.get("organizationId")!;
|
||||
const org = await firstValueFrom(
|
||||
this.organizationService.organizations$(userId).pipe(getById(orgId), takeWhile(Boolean)),
|
||||
);
|
||||
|
||||
this.state.setOrganization(org);
|
||||
|
||||
await firstValueFrom(this.organizationIntegrationService.setOrganizationId(org.id));
|
||||
|
||||
const integrations: Integration[] = [
|
||||
{
|
||||
name: "AD FS",
|
||||
linkURL: "https://bitwarden.com/help/saml-adfs/",
|
||||
image: "../../../../../../../images/integrations/azure-active-directory.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Auth0",
|
||||
linkURL: "https://bitwarden.com/help/saml-auth0/",
|
||||
image: "../../../../../../../images/integrations/logo-auth0-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "AWS",
|
||||
linkURL: "https://bitwarden.com/help/saml-aws/",
|
||||
image: "../../../../../../../images/integrations/aws-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/aws-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/saml-azure/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Duo",
|
||||
linkURL: "https://bitwarden.com/help/saml-duo/",
|
||||
image: "../../../../../../../images/integrations/logo-duo-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Google",
|
||||
linkURL: "https://bitwarden.com/help/saml-google/",
|
||||
image: "../../../../../../../images/integrations/logo-google-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "JumpCloud",
|
||||
linkURL: "https://bitwarden.com/help/saml-jumpcloud/",
|
||||
image: "../../../../../../../images/integrations/logo-jumpcloud-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/jumpcloud-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "KeyCloak",
|
||||
linkURL: "https://bitwarden.com/help/saml-keycloak/",
|
||||
image: "../../../../../../../images/integrations/logo-keycloak-icon.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/saml-okta/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/saml-onelogin/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "PingFederate",
|
||||
linkURL: "https://bitwarden.com/help/saml-pingfederate/",
|
||||
image: "../../../../../../../images/integrations/logo-ping-identity-badge-color.svg",
|
||||
type: IntegrationType.SSO,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-entra-id-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/okta-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/onelogin-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "JumpCloud",
|
||||
linkURL: "https://bitwarden.com/help/jumpcloud-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-jumpcloud-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/jumpcloud-darkmode.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Ping Identity",
|
||||
linkURL: "https://bitwarden.com/help/ping-identity-scim-integration/",
|
||||
image: "../../../../../../../images/integrations/logo-ping-identity-badge-color.svg",
|
||||
type: IntegrationType.SCIM,
|
||||
},
|
||||
{
|
||||
name: "Active Directory",
|
||||
linkURL: "https://bitwarden.com/help/ldap-directory/",
|
||||
image: "../../../../../../../images/integrations/azure-active-directory.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Entra ID",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-entra-id/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-entra-id-color.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Google Workspace",
|
||||
linkURL: "https://bitwarden.com/help/workspace-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-google-badge-color.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Okta",
|
||||
linkURL: "https://bitwarden.com/help/okta-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-okta-symbol-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/okta-darkmode.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "OneLogin",
|
||||
linkURL: "https://bitwarden.com/help/onelogin-directory/",
|
||||
image: "../../../../../../../images/integrations/logo-onelogin-badge-color.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/onelogin-darkmode.svg",
|
||||
type: IntegrationType.BWDC,
|
||||
},
|
||||
{
|
||||
name: "Splunk",
|
||||
linkURL: "https://bitwarden.com/help/splunk-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-splunk-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/splunk-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Microsoft Sentinel",
|
||||
linkURL: "https://bitwarden.com/help/microsoft-sentinel-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-sentinel-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Rapid7",
|
||||
linkURL: "https://bitwarden.com/help/rapid7-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-rapid7-black.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/rapid7-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Elastic",
|
||||
linkURL: "https://bitwarden.com/help/elastic-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-elastic-badge-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Panther",
|
||||
linkURL: "https://bitwarden.com/help/panther-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-panther-round-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
},
|
||||
{
|
||||
name: "Sumo Logic",
|
||||
linkURL: "https://bitwarden.com/help/sumo-logic-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-sumo-logic-siem.svg",
|
||||
imageDarkMode: "../../../../../../../images/integrations/logo-sumo-logic-siem-darkmode.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
newBadgeExpiration: "2025-12-31",
|
||||
},
|
||||
{
|
||||
name: "Microsoft Intune",
|
||||
linkURL: "https://bitwarden.com/help/deploy-browser-extensions-with-intune/",
|
||||
image: "../../../../../../../images/integrations/logo-microsoft-intune-color.svg",
|
||||
type: IntegrationType.DEVICE,
|
||||
},
|
||||
];
|
||||
|
||||
const featureEnabled = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.EventManagementForDataDogAndCrowdStrike),
|
||||
);
|
||||
|
||||
if (featureEnabled) {
|
||||
integrations.push(
|
||||
{
|
||||
name: OrganizationIntegrationServiceName.CrowdStrike,
|
||||
linkURL: "https://bitwarden.com/help/crowdstrike-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-crowdstrike-black.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
canSetupConnection: true,
|
||||
integrationType: OrganizationIntegrationType.Hec,
|
||||
},
|
||||
{
|
||||
name: OrganizationIntegrationServiceName.Datadog,
|
||||
linkURL: "https://bitwarden.com/help/datadog-siem/",
|
||||
image: "../../../../../../../images/integrations/logo-datadog-color.svg",
|
||||
type: IntegrationType.EVENT,
|
||||
canSetupConnection: true,
|
||||
integrationType: OrganizationIntegrationType.Datadog,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Wait for initial integrations load
|
||||
const orgIntegrations = await firstValueFrom(
|
||||
this.organizationIntegrationService.integrations$.pipe(take(1)),
|
||||
);
|
||||
|
||||
const merged = integrations.map((i) => ({
|
||||
...i,
|
||||
organizationIntegration: orgIntegrations.find((o) => o.serviceName === i.name) ?? null,
|
||||
}));
|
||||
|
||||
this.state.setIntegrations(merged);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from "@angular/core";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { Integration } from "@bitwarden/bit-common/dirt/organization-integrations/models/integration";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class OrganizationIntegrationsState {
|
||||
private integrationsSource = new BehaviorSubject<Integration[]>([]);
|
||||
private organizationSource = new BehaviorSubject<Organization>(null);
|
||||
integrations$ = this.integrationsSource.asObservable();
|
||||
organization$ = this.organizationSource.asObservable();
|
||||
|
||||
setOrganization(val: Organization) {
|
||||
this.organizationSource.next(val);
|
||||
}
|
||||
|
||||
setIntegrations(val: Integration[]) {
|
||||
this.integrationsSource.next(val);
|
||||
}
|
||||
|
||||
get organization() {
|
||||
return this.organizationSource.value;
|
||||
}
|
||||
|
||||
get integrations() {
|
||||
return this.integrationsSource.value;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,27 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { IntegrationType } from "@bitwarden/common/enums/integration-type.enum";
|
||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||
|
||||
import { IntegrationGridComponent } from "../integration-grid/integration-grid.component";
|
||||
import { FilterIntegrationsPipe } from "../integrations.pipe";
|
||||
import { OrganizationIntegrationsState } from "../organization-integrations.state";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "single-sign-on",
|
||||
templateUrl: "single-sign-on.component.html",
|
||||
imports: [IntegrationGridComponent, FilterIntegrationsPipe],
|
||||
imports: [SharedModule, IntegrationGridComponent, FilterIntegrationsPipe],
|
||||
})
|
||||
export class SingleSignOnComponent implements OnInit {
|
||||
constructor() {}
|
||||
integrationsList = this.state.integrations;
|
||||
|
||||
constructor(private state: OrganizationIntegrationsState) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get IntegrationType(): typeof IntegrationType {
|
||||
return IntegrationType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
@let organization = organization$ | async;
|
||||
@let integrationsList = integrations$ | async;
|
||||
|
||||
<section class="tw-mb-9" *ngIf="organization?.useScim">
|
||||
<h2 bitTypography="h2">
|
||||
{{ "scimIntegration" | i18n }}
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { IntegrationType } from "@bitwarden/common/enums/integration-type.enum";
|
||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||
|
||||
import { IntegrationGridComponent } from "../integration-grid/integration-grid.component";
|
||||
import { FilterIntegrationsPipe } from "../integrations.pipe";
|
||||
import { OrganizationIntegrationsState } from "../organization-integrations.state";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "user-provisioning",
|
||||
templateUrl: "user-provisioning.component.html",
|
||||
imports: [SharedModule, IntegrationGridComponent, FilterIntegrationsPipe],
|
||||
})
|
||||
export class UserProvisioningComponent implements OnInit {
|
||||
constructor() {}
|
||||
organization$ = this.state.organization$;
|
||||
integrations$ = this.state.integrations$;
|
||||
|
||||
constructor(private state: OrganizationIntegrationsState) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get IntegrationType(): typeof IntegrationType {
|
||||
return IntegrationType;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user