diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index adfcc1b..ddbf352 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -8,6 +8,7 @@ services: ports: - "8001:8000" - "8089:8089" + - "8088:8088" environment: SPLUNK_GENERAL_TERMS: "--accept-sgt-current-at-splunk-com" SPLUNK_START_ARGS: "--accept-license" @@ -19,6 +20,7 @@ services: ports: - "8001:8000" - "8089:8089" + - "8088:8088" environment: SPLUNK_START_ARGS: "--accept-license" SPLUNK_PASSWORD: password diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 5afe25a..546e1c5 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -24,178 +24,220 @@

-

Bitwarden API Key

-

- Your - API key - can be found in the Bitwarden organization Admin Console. -

-
- -
- -
- @if ( - setupForm.controls.clientId.invalid && - setupForm.controls.clientId.touched - ) { -
Client Id is required
- } -
-
- -
- -
- @if ( - setupForm.controls.clientSecret.invalid && - setupForm.controls.clientSecret.touched - ) { -
Client Secret is required
- } -
+

Event Delivery Mode

+ + + + -

Bitwarden Server Url

-

- Self-hosted Bitwarden servers may need to reconfigure their - installation's URL. -

-
- -
- + + + + @if (isPushEventDelivery()) { +

+ To complete setup for receiving event logs with the HEC Event + Collector, follow the instructions in the + - - - - -

-
- + Bitwarden Splunk documentation. +

+ } @else { +

Bitwarden API Key

+

+ Your + API key + can be found in the Bitwarden organization Admin Console. +

+
+ +
+ +
+ @if ( + setupForm.controls.clientId.invalid && + setupForm.controls.clientId.touched + ) { +
Client Id is required
+ }
- @if ( - setupForm.controls.serverUrl.invalid && - setupForm.controls.serverUrl.touched - ) { -
- @if (setupForm.controls.serverUrl.hasError("required")) { - Server Url is required - } @else if (setupForm.controls.serverUrl.hasError("insecureUrl")) { - URLs starting with 'http://' are considered insecure and are not - allowed in Splunk. Please use 'https://' instead. - } @else { - Invalid Url - } +
+ +
+
- } -
+ @if ( + setupForm.controls.clientSecret.invalid && + setupForm.controls.clientSecret.touched + ) { +
Client Secret is required
+ } +
-

Splunk Index

-

Choose a Splunk index for the Bitwarden event logs.

-
- -
- + + + + +
+
+ +
+ @if ( + setupForm.controls.serverUrl.invalid && + setupForm.controls.serverUrl.touched + ) { +
+ @if (setupForm.controls.serverUrl.hasError("required")) { + Server Url is required + } @else if ( + setupForm.controls.serverUrl.hasError("insecureUrl") + ) { + URLs starting with 'http://' are considered insecure and are not + allowed in Splunk. Please use 'https://' instead. + } @else { + Invalid Url } - } @else { - - } - +
+ }
-
- -
- @if ( - setupForm.hasError("indexRequired") && - (setupForm.controls.index.touched || - setupForm.controls.indexOverride.touched) - ) { -
Index is required
- } -
-

Event Logs

-

- Choose the earliest Bitwarden event date to retrieve. The default is 1 - year before today's date.
- This only works for first time setup. Make sure you have no other - Bitwarden events to avoid duplications. -

-
- -
+

Splunk Index

+

Choose a Splunk index for the Bitwarden event logs.

+
+
+ + +
+ @if ( + setupForm.hasError("indexRequired") && + (setupForm.controls.index.touched || + setupForm.controls.indexOverride.touched) + ) { +
Index is required
+ }
-
+ +

Event Logs

+

+ Choose the earliest Bitwarden event date to retrieve. The default is 1 + year before today's date.
+ This only works for first time setup. Make sure you have no other + Bitwarden events to avoid duplications. +

+
+ +
+
+ +
+
+
+ } @if (setupForm.invalid && setupForm.touched) {
; @@ -59,6 +61,7 @@ export class AppComponent { startDate: [""], index: [""], indexOverride: [""], + eventDeliveryMode: ["poll"], }, { validators: indexRequiredValidator(), @@ -104,6 +107,35 @@ export class AppComponent { } }); + // To hide polling setup input fields, keep boolean signal for push delivery mode + this.setupForm.controls.eventDeliveryMode.valueChanges + .pipe( + startWith(this.setupForm.controls.eventDeliveryMode.value), + takeUntilDestroyed(), + ) + .subscribe((eventDeliveryMode) => { + const isPush = eventDeliveryMode === "push"; + this.isPushEventDelivery.set(isPush); + + // disable form validators when push is selected, reapply when polling is selected + if (isPush) { + this.setupForm.controls.clientId.clearValidators(); + this.setupForm.controls.clientSecret.clearValidators(); + this.setupForm.controls.serverUrl.clearValidators(); + this.setupForm.setValidators(null); + this.setupForm.controls.clientId.updateValueAndValidity(); + this.setupForm.controls.clientSecret.updateValueAndValidity(); + this.setupForm.controls.serverUrl.updateValueAndValidity(); + this.setupForm.updateValueAndValidity(); + } else { + this.setupForm.controls.clientId.setValidators(Validators.required); + this.setupForm.controls.clientSecret.setValidators( + Validators.required, + ); + this.setupForm.setValidators(indexRequiredValidator()); + } + }); + // Load indexes const indexesObservable = from(splunkService.getAllIndexes()).pipe( map((indexes) => indexes.map((index) => index.name)), @@ -128,54 +160,12 @@ export class AppComponent { const formValue = this.setupForm.value as SetupForm; try { - // Store secrets - await this.bitwardenSplunkService.upsertApiKey( - formValue.clientId, - formValue.clientSecret, - ); - - // Update inputs.conf - const index = formValue.indexOverride - ? formValue.indexOverride - : formValue.index; - console.debug("Index", index); - await this.bitwardenSplunkService.updateInputsConfigurationFile({ - index, - }); - - // Update script.conf - let apiUrl: string; - let identityUrl: string; - if (this.isServerUrlBitwardenCloud(formValue.serverUrlType)) { - const serverHost = - formValue.serverUrlType === "bitwarden.com" - ? "bitwarden.com" - : "bitwarden.eu"; - apiUrl = `https://api.${serverHost}`; - identityUrl = `https://identity.${serverHost}`; + if (formValue.eventDeliveryMode === "poll") { + await this.submitPollingConfiguration(formValue); } else { - const containsProtocol = /^https?:\/\//.test(formValue.serverUrl); - const serverUrl = new URL( - containsProtocol - ? formValue.serverUrl - : "https://" + formValue.serverUrl, - ); - - if (!serverUrl.pathname.endsWith("/")) { - serverUrl.pathname = serverUrl.pathname + "/"; - } - - apiUrl = serverUrl.href + "api"; - identityUrl = serverUrl.href + "identity"; + await this.submitPushConfiguration(formValue); } - console.debug("Bitwarden urls", apiUrl, identityUrl); - await this.bitwardenSplunkService.updateScriptConfigurationFile({ - apiUrl, - identityUrl, - startDate: formValue.startDate, - }); - // Complete setup await this.bitwardenSplunkService.updateAppConfigurationFile(true); await this.bitwardenSplunkService.reloadApp(); @@ -194,6 +184,63 @@ export class AppComponent { } } + private async submitPollingConfiguration(formValue: SetupForm) { + // Store secrets + await this.bitwardenSplunkService.upsertApiKey( + formValue.clientId, + formValue.clientSecret, + ); + + // Update inputs.conf + const index = formValue.indexOverride + ? formValue.indexOverride + : formValue.index; + console.debug("Index", index); + await this.bitwardenSplunkService.updateInputsConfigurationFile({ + index, + }); + + // Update script.conf + let apiUrl: string; + let identityUrl: string; + if (this.isServerUrlBitwardenCloud(formValue.serverUrlType)) { + const serverHost = + formValue.serverUrlType === "bitwarden.com" + ? "bitwarden.com" + : "bitwarden.eu"; + apiUrl = `https://api.${serverHost}`; + identityUrl = `https://identity.${serverHost}`; + } else { + const containsProtocol = /^https?:\/\//.test(formValue.serverUrl); + const serverUrl = new URL( + containsProtocol + ? formValue.serverUrl + : "https://" + formValue.serverUrl, + ); + + if (!serverUrl.pathname.endsWith("/")) { + serverUrl.pathname = serverUrl.pathname + "/"; + } + + apiUrl = serverUrl.href + "api"; + identityUrl = serverUrl.href + "identity"; + } + + console.debug("Bitwarden urls", apiUrl, identityUrl); + await this.bitwardenSplunkService.updateScriptConfigurationFile({ + apiUrl, + identityUrl, + startDate: formValue.startDate, + eventDeliveryMode: formValue.eventDeliveryMode, + }); + } + + private async submitPushConfiguration(formValue: SetupForm) { + await this.bitwardenSplunkService.updateScriptConfigurationFile({ + eventDeliveryMode: formValue.eventDeliveryMode, + }); + } + private loadConfiguration(indexesObservable: Observable) { combineLatest([ indexesObservable, @@ -220,6 +267,7 @@ export class AppComponent { if ( scriptConfiguration !== undefined && + scriptConfiguration.apiUrl !== undefined && URL.canParse(scriptConfiguration.apiUrl) ) { const apiUrl = new URL(scriptConfiguration.apiUrl); diff --git a/ui/src/models/bitwarden-splunk.ts b/ui/src/models/bitwarden-splunk.ts index dce269c..97d5731 100644 --- a/ui/src/models/bitwarden-splunk.ts +++ b/ui/src/models/bitwarden-splunk.ts @@ -3,7 +3,8 @@ export type InputsConfiguration = { }; export type ScriptsConfiguration = { - apiUrl: string; - identityUrl: string; + apiUrl?: string; + identityUrl?: string; startDate?: string; + eventDeliveryMode?: "poll" | "push"; }; diff --git a/ui/src/models/setup-form.ts b/ui/src/models/setup-form.ts index ee8206b..170a334 100644 --- a/ui/src/models/setup-form.ts +++ b/ui/src/models/setup-form.ts @@ -8,4 +8,5 @@ export type SetupForm = { startDate: string; index: string; indexOverride: string; + eventDeliveryMode: "poll" | "push"; };