1
0
mirror of https://github.com/bitwarden/server synced 2025-12-26 21:23:39 +00:00

[PM-17562] Add HEC integration support (#6010)

* [PM-17562] Add HEC integration support

* Re-ordered parameters per PR suggestion

* Apply suggestions from code review

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>

* Refactored webhook request model validation to be more clear

---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
Brant DeBow
2025-07-01 08:52:38 -04:00
committed by GitHub
parent e8ad23c8bc
commit f6cd661e8e
22 changed files with 302 additions and 67 deletions

View File

@@ -197,22 +197,37 @@ interface and therefore can also handle directly all the message publishing func
Organizations can configure integration configurations to send events to different endpoints -- each
handler maps to a specific integration and checks for the configuration when it receives an event.
Currently, there are integrations / handlers for Slack and webhooks (as mentioned above).
Currently, there are integrations / handlers for Slack, webhooks, and HTTP Event Collector (HEC).
### `OrganizationIntegration`
- The top-level object that enables a specific integration for the organization.
- Includes any properties that apply to the entire integration across all events.
- For Slack, it consists of the token: `{ "token": "xoxb-token-from-slack" }`
- For webhooks, it is `null`. However, even though there is no configuration, an organization must
have a webhook `OrganizationIntegration` to enable configuration via `OrganizationIntegrationConfiguration`.
- For Slack, it consists of the token: `{ "Token": "xoxb-token-from-slack" }`.
- For webhooks, it is optional. Webhooks can either be configured at this level or the configuration level,
but the configuration level takes precedence. However, even though it is optional, an organization must
have a webhook `OrganizationIntegration` (even will a `null` `Configuration`) to enable configuration
via `OrganizationIntegrationConfiguration`.
- For HEC, it consists of the scheme, token, and URI:
```json
{
"Scheme": "Bearer",
"Token": "Auth-token-from-HEC-service",
"Uri": "https://example.com/api"
}
```
### `OrganizationIntegrationConfiguration`
- This contains the configurations specific to each `EventType` for the integration.
- `Configuration` contains the event-specific configuration.
- For Slack, this would contain what channel to send the message to: `{ "channelId": "C123456" }`
- For Webhook, this is the URL the request should be sent to: `{ "url": "https://api.example.com" }`
- For webhooks, this is the URL the request should be sent to: `{ "url": "https://api.example.com" }`
- Optionally this also can include a `Scheme` and `Token` if this webhook needs Authentication.
- As stated above, all of this information can be specified here or at the `OrganizationIntegration`
level, but any properties declared here will take precedence over the ones above.
- For HEC, this must be null. HEC is configured only at the `OrganizationIntegration` level.
- `Template` contains a template string that is expected to be filled in with the contents of the actual event.
- The tokens in the string are wrapped in `#` characters. For instance, the UserId would be `#UserId#`.
- The `IntegrationTemplateProcessor` does the actual work of replacing these tokens with introspected values from
@@ -225,6 +240,8 @@ Currently, there are integrations / handlers for Slack and webhooks (as mentione
- This is the combination of both the `OrganizationIntegration` and `OrganizationIntegrationConfiguration` into
a single object. The combined contents tell the integration's handler all the details needed to send to an
external service.
- `OrganizationIntegrationConfiguration` takes precedence over `OrganizationIntegration` - any keys present in
both will receive the value declared in `OrganizationIntegrationConfiguration`.
- An array of `OrganizationIntegrationConfigurationDetails` is what the `EventIntegrationHandler` fetches from
the database to determine what to publish at the integration level.

View File

@@ -6,8 +6,6 @@ using System.Net.Http.Headers;
using System.Text;
using Bit.Core.AdminConsole.Models.Data.EventIntegrations;
#nullable enable
namespace Bit.Core.Services;
public class WebhookIntegrationHandler(
@@ -21,7 +19,7 @@ public class WebhookIntegrationHandler(
public override async Task<IntegrationHandlerResult> HandleAsync(IntegrationMessage<WebhookIntegrationConfigurationDetails> message)
{
var request = new HttpRequestMessage(HttpMethod.Post, message.Configuration.Url);
var request = new HttpRequestMessage(HttpMethod.Post, message.Configuration.Uri);
request.Content = new StringContent(message.RenderedTemplate, Encoding.UTF8, "application/json");
if (!string.IsNullOrEmpty(message.Configuration.Scheme))
{