[8.17] [Security Solution][Connectors] Torq connector allow EU hooks hostname (#212563) (#213615)

# Backport

This will backport the following commits from `main` to `8.17`:
- [[Security Solution][Connectors] Torq connector allow EU hooks
hostname (#212563)](https://github.com/elastic/kibana/pull/212563)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Sergi
Massaneda","email":"sergi.massaneda@elastic.co"},"sourceCommit":{"committedDate":"2025-03-07T17:43:24Z","message":"[Security
Solution][Connectors] Torq connector allow EU hooks hostname
(#212563)\n\n## Summary\n\nFrom:
https://github.com/elastic/kibana/issues/212511\n\nAdd support for EU
domains\n\n---------\n\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"723a33b7de7b776f39ae816c42eaf2abd07734ba","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:fix","v9.0.0","Team:Threat
Hunting","backport:version","v8.18.0","v9.1.0","v8.19.0","v8.17.3"],"title":"[Security
Solution][Connectors] Torq connector allow EU hooks
hostname","number":212563,"url":"https://github.com/elastic/kibana/pull/212563","mergeCommit":{"message":"[Security
Solution][Connectors] Torq connector allow EU hooks hostname
(#212563)\n\n## Summary\n\nFrom:
https://github.com/elastic/kibana/issues/212511\n\nAdd support for EU
domains\n\n---------\n\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"723a33b7de7b776f39ae816c42eaf2abd07734ba"}},"sourceBranch":"main","suggestedTargetBranches":["8.17"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/213613","number":213613,"state":"OPEN"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/213611","number":213611,"state":"OPEN"},{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212563","number":212563,"mergeCommit":{"message":"[Security
Solution][Connectors] Torq connector allow EU hooks hostname
(#212563)\n\n## Summary\n\nFrom:
https://github.com/elastic/kibana/issues/212511\n\nAdd support for EU
domains\n\n---------\n\nCo-authored-by: Elastic Machine
<elasticmachine@users.noreply.github.com>","sha":"723a33b7de7b776f39ae816c42eaf2abd07734ba"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"url":"https://github.com/elastic/kibana/pull/213612","number":213612,"state":"OPEN"},{"branch":"8.17","label":"v8.17.3","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Sergi Massaneda 2025-03-10 19:06:59 +01:00 committed by GitHub
parent 4a7a5d56eb
commit d62cf5b255
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 68 additions and 5 deletions

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
const hostNameRegExp = /^hooks\.(eu\.)?torq\.io$/;
export const isValidTorqHostName = (hostName: string) => {
return hostNameRegExp.test(hostName);
};

View file

@ -93,6 +93,41 @@ describe('TorqActionConnectorFields renders', () => {
});
});
it('connector validation succeeds when using a EU torq webhook URL', async () => {
const connector = {
...actionConnector,
config: { webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/webhooks/fjdksla' },
};
const { getByTestId } = render(
<ConnectorFormTestProvider connector={connector} onSubmit={onSubmit}>
<TorqActionConnectorFields
readOnly={false}
isEdit={false}
registerPreSubmitValidator={EMPTY_FUNC}
/>
</ConnectorFormTestProvider>
);
await act(async () => {
await userEvent.click(getByTestId('form-test-provide-submit'));
});
expect(onSubmit).toBeCalledWith({
data: {
actionTypeId: '.torq',
name: 'torq',
config: {
webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/webhooks/fjdksla',
},
secrets: {
token: 'testtoken',
},
isDeprecated: false,
},
isValid: true,
});
});
it('connector validation fails when there is no token', async () => {
const connector = {
...actionConnector,
@ -153,7 +188,7 @@ describe('TorqActionConnectorFields renders', () => {
const connector = {
...actionConnector,
config: {
webhookIntegrationUrl: 'https://test.com',
webhookIntegrationUrl: 'https://hooks.not-torq.io/v1/webhooks/fjdksla',
},
};

View file

@ -17,6 +17,7 @@ import {
import { isUrl } from '@kbn/es-ui-shared-plugin/static/validators/string';
import { ActionConnectorFieldsProps } from '@kbn/triggers-actions-ui-plugin/public';
import React from 'react';
import { isValidTorqHostName } from '../../../common/torq';
import * as i18n from './translations';
const { urlField, emptyField } = fieldValidators;
@ -42,7 +43,7 @@ const torqWebhookEndpoint =
};
if (!isUrl(value)) return error;
const hostname = new URL(value).hostname;
return hostname === 'hooks.torq.io' ? undefined : error;
return isValidTorqHostName(hostname) ? undefined : error;
};
const TorqActionConnectorFields: React.FunctionComponent<ActionConnectorFieldsProps> = ({

View file

@ -85,6 +85,15 @@ describe('config validation', () => {
...config,
});
});
test('config validation passes with the EU endpoint', () => {
const config: Record<string, string | boolean> = {
webhookIntegrationUrl: 'https://hooks.eu.torq.io/v1/test',
};
expect(validateConfig(actionType, config, { configurationUtilities })).toEqual({
...defaultValues,
...config,
});
});
const errorCases: Array<{ name: string; url: string; errorMsg: string }> = [
{
@ -100,7 +109,12 @@ describe('config validation', () => {
{
name: 'fails when URL is not a Torq webhook endpoint',
url: 'http://mylisteningserver:9200/endpoint',
errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io"`,
errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io"`,
},
{
name: 'fails when URL is an unsupported Torq webhook subdomain',
url: 'https://hooks.anothersubdomain.torq.io/v1/test',
errorMsg: `"error validating action type config: error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io"`,
},
];
errorCases.forEach(({ name, url, errorMsg }) => {

View file

@ -22,6 +22,7 @@ import {
import { renderMustacheObject } from '@kbn/actions-plugin/server/lib/mustache_renderer';
import { request } from '@kbn/actions-plugin/server/lib/axios_utils';
import { ValidatorServices } from '@kbn/actions-plugin/server/types';
import { isValidTorqHostName } from '../../../common/torq';
import { getRetryAfterIntervalFromHeaders } from '../lib/http_response_retry_header';
import { promiseResult, isOk, Result } from '../lib/result_type';
@ -128,11 +129,11 @@ function validateActionTypeConfig(
);
}
if (configureUrlObj.hostname !== 'hooks.torq.io' && configureUrlObj.hostname !== 'localhost') {
if (!isValidTorqHostName(configureUrlObj.hostname) && configureUrlObj.hostname !== 'localhost') {
throw new Error(
i18n.translate('xpack.stackConnectors.torq.torqConfigurationErrorInvalidHostname', {
defaultMessage:
'error configuring send to Torq action: url must begin with https://hooks.torq.io',
'error configuring send to Torq action: url must begin with https://hooks.torq.io or https://hooks.eu.torq.io',
})
);
}