[PM-26971] Fix DataDog and Crowdstrike Integration (#18024)

This commit is contained in:
Vijay Oommen
2025-12-17 15:19:06 -06:00
committed by GitHub
parent ea45c5d3c0
commit 4061710790
8 changed files with 116 additions and 38 deletions

View File

@@ -4,15 +4,19 @@ import { OrganizationIntegrationServiceName } from "../organization-integration-
export class DatadogConfiguration implements OrgIntegrationConfiguration {
uri: string;
apiKey: string;
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
constructor(uri: string, apiKey: string, service: OrganizationIntegrationServiceName) {
constructor(uri: string, apiKey: string, bw_serviceName: OrganizationIntegrationServiceName) {
this.uri = uri;
this.apiKey = apiKey;
this.service = service;
this.bw_serviceName = bw_serviceName;
}
toString(): string {
return JSON.stringify(this);
toString() {
return JSON.stringify({
Uri: this.uri,
ApiKey: this.apiKey,
bw_serviceName: this.bw_serviceName,
});
}
}

View File

@@ -5,15 +5,21 @@ export class HecConfiguration implements OrgIntegrationConfiguration {
uri: string;
scheme = "Bearer";
token: string;
service: OrganizationIntegrationServiceName;
service?: string;
bw_serviceName: OrganizationIntegrationServiceName;
constructor(uri: string, token: string, service: OrganizationIntegrationServiceName) {
constructor(uri: string, token: string, bw_serviceName: OrganizationIntegrationServiceName) {
this.uri = uri;
this.token = token;
this.service = service;
this.bw_serviceName = bw_serviceName;
}
toString(): string {
return JSON.stringify(this);
return JSON.stringify({
Uri: this.uri,
Scheme: this.scheme,
Token: this.token,
bw_serviceName: this.bw_serviceName,
});
}
}

View File

@@ -5,12 +5,12 @@ import { OrganizationIntegrationServiceName } from "../organization-integration-
export class WebhookConfiguration implements OrgIntegrationConfiguration {
propA: string;
propB: string;
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
constructor(propA: string, propB: string, service: OrganizationIntegrationServiceName) {
constructor(propA: string, propB: string, bw_serviceName: OrganizationIntegrationServiceName) {
this.propA = propA;
this.propB = propB;
this.service = service;
this.bw_serviceName = bw_serviceName;
}
toString(): string {

View File

@@ -9,7 +9,7 @@ import { OrganizationIntegrationType } from "./organization-integration-type";
* Defines the structure for organization integration configuration
*/
export interface OrgIntegrationConfiguration {
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
toString(): string;
}
@@ -17,7 +17,7 @@ export interface OrgIntegrationConfiguration {
* Defines the structure for organization integration template
*/
export interface OrgIntegrationTemplate {
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
toString(): string;
}
@@ -28,24 +28,26 @@ export class OrgIntegrationBuilder {
static buildHecConfiguration(
uri: string,
token: string,
service: OrganizationIntegrationServiceName,
bw_serviceName: OrganizationIntegrationServiceName,
): OrgIntegrationConfiguration {
return new HecConfiguration(uri, token, service);
return new HecConfiguration(uri, token, bw_serviceName);
}
static buildHecTemplate(
index: string,
service: OrganizationIntegrationServiceName,
bw_serviceName: OrganizationIntegrationServiceName,
): OrgIntegrationTemplate {
return new HecTemplate(index, service);
return new HecTemplate(index, bw_serviceName);
}
static buildDataDogConfiguration(uri: string, apiKey: string): OrgIntegrationConfiguration {
return new DatadogConfiguration(uri, apiKey, OrganizationIntegrationServiceName.Datadog);
}
static buildDataDogTemplate(service: OrganizationIntegrationServiceName): OrgIntegrationTemplate {
return new DatadogTemplate(service);
static buildDataDogTemplate(
bw_serviceName: OrganizationIntegrationServiceName,
): OrgIntegrationTemplate {
return new DatadogTemplate(bw_serviceName);
}
static buildConfiguration(
@@ -55,7 +57,7 @@ export class OrgIntegrationBuilder {
switch (type) {
case OrganizationIntegrationType.Hec: {
const hecConfig = this.convertToJson<HecConfiguration>(configuration);
return this.buildHecConfiguration(hecConfig.uri, hecConfig.token, hecConfig.service);
return this.buildHecConfiguration(hecConfig.uri, hecConfig.token, hecConfig.bw_serviceName);
}
case OrganizationIntegrationType.Datadog: {
const datadogConfig = this.convertToJson<DatadogConfiguration>(configuration);
@@ -73,11 +75,11 @@ export class OrgIntegrationBuilder {
switch (type) {
case OrganizationIntegrationType.Hec: {
const hecTemplate = this.convertToJson<HecTemplate>(template);
return this.buildHecTemplate(hecTemplate.index, hecTemplate.service);
return this.buildHecTemplate(hecTemplate.index, hecTemplate.bw_serviceName);
}
case OrganizationIntegrationType.Datadog: {
const datadogTemplate = this.convertToJson<DatadogTemplate>(template);
return this.buildDataDogTemplate(datadogTemplate.service);
return this.buildDataDogTemplate(datadogTemplate.bw_serviceName);
}
default:
throw new Error(`Unsupported integration type: ${type}`);
@@ -86,9 +88,33 @@ export class OrgIntegrationBuilder {
private static convertToJson<T>(jsonString?: string): T {
try {
return JSON.parse(jsonString || "{}") as T;
const parsed = JSON.parse(jsonString || "{}");
return this.normalizePropertyCase(parsed) as T;
} catch {
throw new Error("Invalid integration configuration: JSON parse error");
}
}
/**
* Recursively normalizes object property names to camelCase
* Converts the first character of each property to lowercase
*/
private static normalizePropertyCase(obj: any): any {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
return obj.map((item) => this.normalizePropertyCase(item));
}
const normalized: any = {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
const normalizedKey = key.charAt(0).toLowerCase() + key.slice(1);
normalized[normalizedKey] = this.normalizePropertyCase(obj[key]);
}
}
return normalized;
}
}

View File

@@ -2,17 +2,54 @@ import { OrgIntegrationTemplate } from "../../integration-builder";
import { OrganizationIntegrationServiceName } from "../../organization-integration-service-type";
export class DatadogTemplate implements OrgIntegrationTemplate {
source_type_name = "Bitwarden";
title: string = "#Title#";
text: string =
"ActingUser: #ActingUserId#\nUser: #UserId#\nEvent: #Type#\nOrganization: #OrganizationId#\nPolicyId: #PolicyId#\nIpAddress: #IpAddress#\nDomainName: #DomainName#\nCipherId: #CipherId#\n";
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
constructor(service: OrganizationIntegrationServiceName) {
this.service = service;
this.bw_serviceName = service;
}
private toJSON() {
return {
bw_serviceName: this.bw_serviceName,
ddsource: "bitwarden",
service: "event-logs",
event: {
service: "payments",
object: "event",
type: "#Type#",
itemId: "#CipherId#",
collectionId: "#CollectionId#",
groupId: "#GroupId#",
policyId: "#PolicyId#",
memberId: "#UserId#",
actingUserId: "#ActingUserId#",
installationId: "#InstallationId#",
date: "#DateIso8601#",
device: "#DeviceType#",
ipAddress: "#IpAddress#",
secretId: "#SecretId#",
projectId: "#ProjectId#",
serviceAccountId: "#ServiceAccountId#",
},
enrichment_details: {
actingUser: {
name: "#ActingUserName#",
email: "#ActingUserEmail#",
type: "#ActingUserType#",
},
member: {
name: "#UserName#",
email: "#UserEmail#",
type: "#UserType#",
},
group: {
name: "#GroupName#",
},
},
};
}
toString(): string {
return JSON.stringify(this);
return JSON.stringify(this.toJSON());
}
}

View File

@@ -5,14 +5,19 @@ export class HecTemplate implements OrgIntegrationTemplate {
event = "#EventMessage#";
source = "Bitwarden";
index: string;
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
constructor(index: string, service: OrganizationIntegrationServiceName) {
this.index = index;
this.service = service;
this.bw_serviceName = service;
}
toString(): string {
return JSON.stringify(this);
return JSON.stringify({
Event: this.event,
Source: this.source,
Index: this.index,
bw_serviceName: this.bw_serviceName,
});
}
}

View File

@@ -3,12 +3,12 @@ import { OrganizationIntegrationServiceName } from "../../organization-integrati
// Added to reflect how future webhook integrations could be structured within the OrganizationIntegration
export class WebhookTemplate implements OrgIntegrationTemplate {
service: OrganizationIntegrationServiceName;
bw_serviceName: OrganizationIntegrationServiceName;
propA: string;
propB: string;
constructor(service: OrganizationIntegrationServiceName, propA: string, propB: string) {
this.service = service;
constructor(bw_serviceName: OrganizationIntegrationServiceName, propA: string, propB: string) {
this.bw_serviceName = bw_serviceName;
this.propA = propA;
this.propB = propB;
}

View File

@@ -266,7 +266,7 @@ export class OrganizationIntegrationService {
return new OrganizationIntegration(
integrationResponse.id,
integrationResponse.type,
config.service,
config.bw_serviceName,
config,
[integrationConfig],
);