diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index 7fabc3bbcb772..3a5e8ff55ff65 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -196,6 +196,7 @@ enabled: - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/config.ts - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/with_aws_ses_kibana_config/config.ts - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/shared/config.ts + - x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/config.ts - x-pack/test/functional/apps/advanced_settings/config.ts - x-pack/test/functional/apps/aiops/config.ts - x-pack/test/functional/apps/api_keys/config.ts diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 26288d723f18a..1afb5269f0fc1 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -605,6 +605,9 @@ Sets the number of actions that will run ephemerally. To use this, enable ephemeral tasks in task manager first with <> +`xpack.actions.webhook.ssl.pfx.enabled` {ess-icon}:: +Disable PFX file support for SSL client authentication. When set to `false`, the application will not accept PFX certificate files and will require separate certificate and private key files instead. Only applies to the [Webhook connector](/reference/connectors-kibana/webhook-action-type.md). + `xpack.alerting.cancelAlertsOnRuleTimeout` {ess-icon}:: Specifies whether to skip writing alerts and scheduling actions if rule processing was cancelled due to a timeout. Default: `true`. This setting can be diff --git a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker index 7610d9d91ea71..aa6a1f7c93ed9 100755 --- a/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker +++ b/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker @@ -232,6 +232,7 @@ kibana_vars=( xpack.actions.responseTimeout xpack.actions.ssl.proxyVerificationMode xpack.actions.ssl.verificationMode + xpack.actions.webhook.ssl.pfx.enabled xpack.alerting.healthCheck.interval xpack.alerting.invalidateApiKeysTask.interval xpack.alerting.invalidateApiKeysTask.removalDelay diff --git a/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts b/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts index 2789eae1c0a99..bd829ea83ba51 100644 --- a/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/src/platform/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -205,6 +205,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'vis_type_xy.readOnly (boolean?|never)', 'vis_type_vega.enableExternalUrls (boolean?)', 'xpack.actions.email.domain_allowlist (array?)', + 'xpack.actions.webhook.ssl.pfx.enabled (boolean?)', 'xpack.apm.serviceMapEnabled (boolean?)', 'xpack.apm.ui.enabled (boolean?)', 'xpack.apm.ui.maxTraceItems (number?)', diff --git a/x-pack/platform/plugins/shared/actions/public/plugin.test.ts b/x-pack/platform/plugins/shared/actions/public/plugin.test.ts index 2decdf777084f..6f678544be1f9 100644 --- a/x-pack/platform/plugins/shared/actions/public/plugin.test.ts +++ b/x-pack/platform/plugins/shared/actions/public/plugin.test.ts @@ -62,5 +62,20 @@ describe('Actions Plugin', () => { ] `); }); + + it('returns isWebhookSslWithPfxEnabled if set in kibana config', async () => { + const context = coreMock.createPluginInitializerContext({ + webhook: { + ssl: { + pfx: { + enabled: false, + }, + }, + }, + }); + const plugin = new Plugin(context); + const pluginSetup = plugin.setup(); + expect(pluginSetup.isWebhookSslWithPfxEnabled).toBe(false); + }); }); }); diff --git a/x-pack/platform/plugins/shared/actions/public/plugin.ts b/x-pack/platform/plugins/shared/actions/public/plugin.ts index ed718f17955a0..e773d4016b328 100644 --- a/x-pack/platform/plugins/shared/actions/public/plugin.ts +++ b/x-pack/platform/plugins/shared/actions/public/plugin.ts @@ -14,26 +14,37 @@ export interface ActionsPublicPluginSetup { emails: string[], options?: ValidateEmailAddressesOptions ): ValidatedEmail[]; + isWebhookSslWithPfxEnabled?: boolean; } export interface Config { email: { domain_allowlist: string[]; }; + webhook: { + ssl: { + pfx: { + enabled: boolean; + }; + }; + }; } export class Plugin implements CorePlugin { private readonly allowedEmailDomains: string[] | null = null; + private readonly webhookSslWithPfxEnabled: boolean; constructor(ctx: PluginInitializerContext) { const config = ctx.config.get(); this.allowedEmailDomains = config.email?.domain_allowlist || null; + this.webhookSslWithPfxEnabled = config.webhook?.ssl.pfx.enabled ?? true; } public setup(): ActionsPublicPluginSetup { return { validateEmailAddresses: (emails: string[], options: ValidateEmailAddressesOptions) => validateEmails(this.allowedEmailDomains, emails, options), + isWebhookSslWithPfxEnabled: this.webhookSslWithPfxEnabled, }; } diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts index 5e3943e5b2cee..2ac5f73f356f3 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.mock.ts @@ -36,6 +36,13 @@ const createActionsConfigMock = () => { getMaxAttempts: jest.fn().mockReturnValue(3), enableFooterInEmail: jest.fn().mockReturnValue(true), getMaxQueued: jest.fn().mockReturnValue(1000), + getWebhookSettings: jest.fn().mockReturnValue({ + ssl: { + pfx: { + enabled: true, + }, + }, + }), getAwsSesConfig: jest.fn().mockReturnValue(null), }; return mocked; diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts index 7a58ee2d08503..47d861b47a75d 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.test.ts @@ -593,6 +593,56 @@ describe('getMaxQueued()', () => { }); }); +describe('getWebhookSettings()', () => { + test('returns the webhook settings from config', () => { + const config: ActionsConfig = { + ...defaultActionsConfig, + webhook: { + ssl: { + pfx: { + enabled: true, + }, + }, + }, + }; + const webhookSettings = getActionsConfigurationUtilities(config).getWebhookSettings(); + expect(webhookSettings).toEqual({ + ssl: { + pfx: { + enabled: true, + }, + }, + }); + }); + + test('returns the webhook settings from config when pfx is false', () => { + const config: ActionsConfig = { + ...defaultActionsConfig, + webhook: { + ssl: { + pfx: { + enabled: false, + }, + }, + }, + }; + const webhookSettings = getActionsConfigurationUtilities(config).getWebhookSettings(); + expect(webhookSettings).toEqual({ + ssl: { + pfx: { + enabled: false, + }, + }, + }); + }); + + test('returns true when no webhook settings are defined', () => { + const config: ActionsConfig = defaultActionsConfig; + const webhookSettings = getActionsConfigurationUtilities(config).getWebhookSettings(); + expect(webhookSettings).toEqual({ ssl: { pfx: { enabled: true } } }); + }); +}); + describe('getAwsSesConfig()', () => { test('returns null when no email config set', () => { const acu = getActionsConfigurationUtilities(defaultActionsConfig); diff --git a/x-pack/platform/plugins/shared/actions/server/actions_config.ts b/x-pack/platform/plugins/shared/actions/server/actions_config.ts index 6210901af6c10..18d61fe32679e 100644 --- a/x-pack/platform/plugins/shared/actions/server/actions_config.ts +++ b/x-pack/platform/plugins/shared/actions/server/actions_config.ts @@ -55,6 +55,13 @@ export interface ActionsConfigurationUtilities { ): string | undefined; enableFooterInEmail: () => boolean; getMaxQueued: () => number; + getWebhookSettings(): { + ssl: { + pfx: { + enabled: boolean; + }; + }; + }; getAwsSesConfig: () => AwsSesConfig; } @@ -230,6 +237,15 @@ export function getActionsConfigurationUtilities( }, enableFooterInEmail: () => config.enableFooterInEmail, getMaxQueued: () => config.queued?.max || DEFAULT_QUEUED_MAX, + getWebhookSettings: () => { + return { + ssl: { + pfx: { + enabled: config.webhook?.ssl.pfx.enabled ?? true, + }, + }, + }; + }, getAwsSesConfig: () => { if (config.email?.services?.ses.host && config.email?.services?.ses.port) { return { diff --git a/x-pack/platform/plugins/shared/actions/server/config.test.ts b/x-pack/platform/plugins/shared/actions/server/config.test.ts index 67660410c4372..1735212e6d51a 100644 --- a/x-pack/platform/plugins/shared/actions/server/config.test.ts +++ b/x-pack/platform/plugins/shared/actions/server/config.test.ts @@ -258,6 +258,32 @@ describe('config validation', () => { expect(result.email?.domain_allowlist).toEqual(['a.com', 'b.c.com', 'd.e.f.com']); }); + test('validates xpack.actions.webhook', () => { + const config: Record = {}; + let result = configSchema.validate(config); + expect(result.webhook === undefined); + + config.webhook = {}; + result = configSchema.validate(config); + expect(result.webhook?.ssl.pfx.enabled).toEqual(true); + + config.webhook = { ssl: {} }; + result = configSchema.validate(config); + expect(result.webhook?.ssl.pfx.enabled).toEqual(true); + + config.webhook = { ssl: { pfx: {} } }; + result = configSchema.validate(config); + expect(result.webhook?.ssl.pfx.enabled).toEqual(true); + + config.webhook = { ssl: { pfx: { enabled: false } } }; + result = configSchema.validate(config); + expect(result.webhook?.ssl.pfx.enabled).toEqual(false); + + config.webhook = { ssl: { pfx: { enabled: true } } }; + result = configSchema.validate(config); + expect(result.webhook?.ssl.pfx.enabled).toEqual(true); + }); + describe('email.services.ses', () => { const config: Record = {}; test('validates no email config at all', () => { diff --git a/x-pack/platform/plugins/shared/actions/server/config.ts b/x-pack/platform/plugins/shared/actions/server/config.ts index d05d0dbbe551b..7e874783fe273 100644 --- a/x-pack/platform/plugins/shared/actions/server/config.ts +++ b/x-pack/platform/plugins/shared/actions/server/config.ts @@ -179,6 +179,15 @@ export const configSchema = schema.object({ }) ), }), + webhook: schema.maybe( + schema.object({ + ssl: schema.object({ + pfx: schema.object({ + enabled: schema.boolean({ defaultValue: true }), + }), + }), + }) + ), }); export type ActionsConfig = TypeOf; diff --git a/x-pack/platform/plugins/shared/actions/server/index.ts b/x-pack/platform/plugins/shared/actions/server/index.ts index 698ca0f6debd1..40597adff3e21 100644 --- a/x-pack/platform/plugins/shared/actions/server/index.ts +++ b/x-pack/platform/plugins/shared/actions/server/index.ts @@ -51,6 +51,7 @@ export const config: PluginConfigDescriptor = { schema: configSchema, exposeToBrowser: { email: { domain_allowlist: true }, + webhook: { ssl: { pfx: { enabled: true } } }, }, deprecations: ({ renameFromRoot, unused }) => [ renameFromRoot('xpack.actions.whitelistedHosts', 'xpack.actions.allowedHosts', { diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/auth_config.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/auth_config.tsx index 8a4bfe6520885..819923471a7c7 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/auth_config.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/auth_config.tsx @@ -39,13 +39,14 @@ import * as i18n from './translations'; interface Props { readOnly: boolean; + isPfxEnabled?: boolean; } const { emptyField } = fieldValidators; const VERIFICATION_MODE_DEFAULT = 'full'; -export const AuthConfig: FunctionComponent = ({ readOnly }) => { +export const AuthConfig: FunctionComponent = ({ readOnly, isPfxEnabled = true }) => { const { setFieldValue, getFieldDefaultValue } = useFormContext(); const [{ config, __internal__ }] = useFormData({ watch: [ @@ -112,6 +113,7 @@ export const AuthConfig: FunctionComponent = ({ readOnly }) => { readOnly={readOnly} certTypeDefaultValue={certTypeDefaultValue} certType={certType} + isPfxEnabled={isPfxEnabled} /> ), 'data-test-subj': 'authSSL', @@ -180,7 +182,7 @@ export const AuthConfig: FunctionComponent = ({ readOnly }) => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label={i18n.DELETE_BUTTON} - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx index cb7b040a2d5d7..eba065b0ee0a1 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.test.tsx @@ -11,10 +11,26 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { SSLCertType } from '../../../common/auth/constants'; import { AuthFormTestProvider } from '../../connector_types/lib/test_utils'; +import { useConnectorContext } from '@kbn/triggers-actions-ui-plugin/public'; +import * as i18n from './translations'; const certTypeDefaultValue: SSLCertType = SSLCertType.CRT; +jest.mock('@kbn/triggers-actions-ui-plugin/public', () => ({ + useConnectorContext: jest.fn(), +})); + describe('SSLCertFields', () => { + beforeEach(() => { + (useConnectorContext as jest.Mock).mockReturnValue({ + services: { isWebhookSslWithPfxEnabled: true }, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + const onSubmit = jest.fn(); it('renders all fields for certType=CRT', async () => { @@ -221,3 +237,33 @@ describe('SSLCertFields', () => { }); }); }); + +describe('validation with PFX disabled', () => { + beforeEach(() => { + (useConnectorContext as jest.Mock).mockReturnValue({ + services: { isWebhookSslWithPfxEnabled: false }, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('does not render PFX tab when PFX is disabled', async () => { + render( + + + + ); + + expect(await screen.findByTestId('sslCertFields')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookSSLPassphraseInput')).toBeInTheDocument(); + expect(await screen.findByTestId('webhookCertTypeTabs')).toBeInTheDocument(); + expect(screen.queryByText(i18n.CERT_TYPE_PFX)).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.tsx index cf9dc672dde33..bb1296a31a165 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/common/auth/ssl_cert_fields.tsx @@ -22,12 +22,14 @@ interface BasicAuthProps { readOnly: boolean; certTypeDefaultValue: SSLCertType; certType: SSLCertType; + isPfxEnabled?: boolean; } export const SSLCertFields: React.FC = ({ readOnly, certTypeDefaultValue, certType, + isPfxEnabled = true, }) => ( @@ -52,21 +54,25 @@ export const SSLCertFields: React.FC = ({ field.setValue(SSLCertType.CRT)} - isSelected={field.value === SSLCertType.CRT} + isSelected={field.value === SSLCertType.CRT || !isPfxEnabled} + data-test-subj="webhookCertTypeCRTab" > {i18n.CERT_TYPE_CRT_KEY} - field.setValue(SSLCertType.PFX)} - isSelected={field.value === SSLCertType.PFX} - > - {i18n.CERT_TYPE_PFX} - + {isPfxEnabled && ( + field.setValue(SSLCertType.PFX)} + isSelected={field.value === SSLCertType.PFX} + data-test-subj="webhookCertTypePFXTab" + > + {i18n.CERT_TYPE_PFX} + + )} )} /> - {certType === SSLCertType.CRT && ( + {(!isPfxEnabled || certType === SSLCertType.CRT) && ( = ({ )} - {certType === SSLCertType.PFX && ( + {isPfxEnabled && certType === SSLCertType.PFX && ( {currentStep < 4 && ( - + )} {currentStep > 1 && ( - + = ({ children, defaultValue, onSubmit, - connectorServices = { validateEmailAddresses: jest.fn() }, + connectorServices = { + validateEmailAddresses: jest.fn(), + isWebhookSslWithPfxEnabled: true, + }, }) => { const { form } = useForm({ defaultValue }); const { submit } = form; diff --git a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx index 0c567127e4811..01f86d76f0f78 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx +++ b/x-pack/platform/plugins/shared/stack_connectors/public/connector_types/webhook/webhook_connectors.tsx @@ -11,7 +11,10 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { UseField } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import { Field, SelectField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import { fieldValidators } from '@kbn/es-ui-shared-plugin/static/forms/helpers'; -import type { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public'; +import { + useConnectorContext, + type ActionConnectorFieldsProps, +} from '@kbn/triggers-actions-ui-plugin/public'; import * as i18n from './translations'; import { AuthConfig } from '../../common/auth/auth_config'; @@ -22,6 +25,10 @@ const { emptyField, urlField } = fieldValidators; const WebhookActionConnectorFields: React.FunctionComponent = ({ readOnly, }) => { + const { + services: { isWebhookSslWithPfxEnabled: isPfxEnabled }, + } = useConnectorContext(); + return ( <> @@ -67,7 +74,7 @@ const WebhookActionConnectorFields: React.FunctionComponent - + ); }; diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.test.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.test.ts index 0f7115adc3d56..17fd89aada72b 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.test.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.test.ts @@ -222,7 +222,7 @@ describe('config validation', () => { expect(() => { validateConfig(connectorType, config, { configurationUtilities }); }).toThrowErrorMatchingInlineSnapshot( - '"error validating action type config: error configuring webhook action: unable to parse url: TypeError: Invalid URL: example.com/do-something"' + `"error validating action type config: error validation webhook action config: unable to parse url: TypeError: Invalid URL: example.com/do-something"` ); }); @@ -295,7 +295,25 @@ describe('config validation', () => { expect(() => { validateConfig(connectorType, config, { configurationUtilities: configUtils }); }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type config: error configuring webhook action: target url is not present in allowedHosts"` + `"error validating action type config: error validation webhook action config: target url is not present in allowedHosts"` + ); + }); + + test('config validation fails when using disabled pfx certType', () => { + const config: Record = { + url: 'https://mylisteningserver:9200/endpoint', + method: WebhookMethods.POST, + authType: AuthType.SSL, + certType: SSLCertType.PFX, + hasAuth: true, + }; + configurationUtilities.getWebhookSettings = jest.fn(() => ({ + ssl: { pfx: { enabled: false } }, + })); + expect(() => { + validateConfig(connectorType, config, { configurationUtilities }); + }).toThrowErrorMatchingInlineSnapshot( + `"error validating action type config: error validation webhook action config: certType \\"ssl-pfx\\" is disabled"` ); }); }); diff --git a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.ts b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.ts index 4788998ed036c..471e0f7eacc69 100644 --- a/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.ts +++ b/x-pack/platform/plugins/shared/stack_connectors/server/connector_types/webhook/index.ts @@ -26,6 +26,7 @@ import { import { renderMustacheString } from '@kbn/actions-plugin/server/lib/mustache_renderer'; import { combineHeadersWithBasicAuthHeader } from '@kbn/actions-plugin/server/lib'; +import { SSLCertType } from '../../../common/auth/constants'; import type { WebhookConnectorType, ActionParamsType, @@ -95,7 +96,7 @@ function validateConnectorTypeConfig( } catch (err) { throw new Error( i18n.translate('xpack.stackConnectors.webhook.configurationErrorNoHostname', { - defaultMessage: 'error configuring webhook action: unable to parse url: {err}', + defaultMessage: 'error validation webhook action config: unable to parse url: {err}', values: { err: err.toString(), }, @@ -108,7 +109,7 @@ function validateConnectorTypeConfig( } catch (allowListError) { throw new Error( i18n.translate('xpack.stackConnectors.webhook.configurationError', { - defaultMessage: 'error configuring webhook action: {message}', + defaultMessage: 'error validation webhook action config: {message}', values: { message: allowListError.message, }, @@ -120,10 +121,25 @@ function validateConnectorTypeConfig( throw new Error( i18n.translate('xpack.stackConnectors.webhook.authConfigurationError', { defaultMessage: - 'error configuring webhook action: authType must be null or undefined if hasAuth is false', + 'error validation webhook action config: authType must be null or undefined if hasAuth is false', }) ); } + + if (configObject.certType === SSLCertType.PFX) { + const webhookSettings = configurationUtilities.getWebhookSettings(); + if (!webhookSettings.ssl.pfx.enabled) { + throw new Error( + i18n.translate('xpack.stackConnectors.webhook.pfxConfigurationError', { + defaultMessage: + 'error validation webhook action config: certType "{certType}" is disabled', + values: { + certType: SSLCertType.PFX, + }, + }) + ); + } + } } // action executor diff --git a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx index d4a03747e6b27..6b4270a0ed427 100644 --- a/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx +++ b/x-pack/platform/plugins/shared/triggers_actions_ui/public/application/connectors_app.tsx @@ -90,11 +90,11 @@ export const App = ({ deps }: { deps: TriggersAndActionsUiServices }) => { export const AppWithoutRouter = ({ sectionsRegex }: { sectionsRegex: string }) => { const { - actions: { validateEmailAddresses }, + actions: { validateEmailAddresses, isWebhookSslWithPfxEnabled }, } = useKibana().services; return ( - + { loadTestFile(require.resolve('./opsgenie')); loadTestFile(require.resolve('./tines')); loadTestFile(require.resolve('./slack')); + loadTestFile(require.resolve('./webhook')); }); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook.ts new file mode 100644 index 0000000000000..79015ac1366ba --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + + describe('webhook', () => { + beforeEach(async () => { + await pageObjects.common.navigateToApp('triggersActionsConnectors'); + }); + + it('should render the cr and pfx tab for ssl auth', async () => { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + await testSubjects.click('.webhook-card'); + await testSubjects.click('authSSL'); + + const certTypeTabs = await find.allByCssSelector( + '[data-test-subj="webhookCertTypeTabs"] > .euiTab' + ); + expect(certTypeTabs.length).to.be(2); + expect(await certTypeTabs[0].getAttribute('data-test-subj')).to.be('webhookCertTypeCRTab'); + expect(await certTypeTabs[1].getAttribute('data-test-subj')).to.be('webhookCertTypePFXTab'); + }); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/config.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/config.ts new file mode 100644 index 0000000000000..aa552249bfe65 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/config.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseConfig = await readConfigFile(require.resolve('../../../../config.base.ts')); + + return { + ...baseConfig.getAll(), + testFiles: [require.resolve('.')], + junit: { + reportName: 'Chrome X-Pack UI Functional Tests with ES SSL - Disabled Webhook SSL PFX', + }, + kbnTestServer: { + ...baseConfig.getAll().kbnTestServer, + serverArgs: [ + ...baseConfig.getAll().kbnTestServer.serverArgs, + `--xpack.actions.webhook.ssl.pfx.enabled=false`, + ], + }, + }; +} diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/index.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/index.ts new file mode 100644 index 0000000000000..2c5741795d657 --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('Webhook - disabled ssl pfx', function () { + loadTestFile(require.resolve('./webhook')); + }); +}; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/webhook.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/webhook.ts new file mode 100644 index 0000000000000..e2de35488effe --- /dev/null +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/webhook_disabled_ssl_pfx/webhook.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const testSubjects = getService('testSubjects'); + const find = getService('find'); + const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + + describe('webhook', () => { + beforeEach(async () => { + await pageObjects.common.navigateToApp('triggersActionsConnectors'); + }); + + it('should not render the pfx tab for ssl auth', async () => { + await pageObjects.triggersActionsUI.clickCreateConnectorButton(); + await testSubjects.click('.webhook-card'); + await testSubjects.click('authSSL'); + + const certTypeTabs = await find.allByCssSelector( + '[data-test-subj="webhookCertTypeTabs"] > .euiTab' + ); + expect(certTypeTabs.length).to.be(1); + expect(await certTypeTabs[0].getAttribute('data-test-subj')).to.be('webhookCertTypeCRTab'); + }); + }); +};