Skip to content

Commit 6ff3bc2

Browse files
Make xpack.actions.rejectUnauthorized setting work (#88690)
* Remove ActionsConfigType due to being a duplicate * Fix rejectUnauthorized not being configured * Move proxySettings to configurationUtilities * Fix isAxiosError check to code * Add functional test * Remove comment * Close webhook server Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent 4fea9ee commit 6ff3bc2

38 files changed

Lines changed: 597 additions & 371 deletions

x-pack/plugins/actions/server/actions_client.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ describe('create()', () => {
402402
enabled: true,
403403
enabledActionTypes: ['some-not-ignored-action-type'],
404404
allowedHosts: ['*'],
405+
preconfigured: {},
406+
proxyRejectUnauthorizedCertificates: true,
407+
rejectUnauthorized: true,
405408
});
406409

407410
const localActionTypeRegistryParams = {

x-pack/plugins/actions/server/actions_config.mock.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const createActionsConfigMock = () => {
1414
ensureHostnameAllowed: jest.fn().mockReturnValue({}),
1515
ensureUriAllowed: jest.fn().mockReturnValue({}),
1616
ensureActionTypeEnabled: jest.fn().mockReturnValue({}),
17+
isRejectUnauthorizedCertificatesEnabled: jest.fn().mockReturnValue(true),
18+
getProxySettings: jest.fn().mockReturnValue(undefined),
1719
};
1820
return mocked;
1921
};

x-pack/plugins/actions/server/actions_config.test.ts

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,26 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { ActionsConfigType } from './types';
7+
import { ActionsConfig } from './config';
88
import {
99
getActionsConfigurationUtilities,
1010
AllowedHosts,
1111
EnabledActionTypes,
1212
} from './actions_config';
1313

14-
const DefaultActionsConfig: ActionsConfigType = {
14+
const defaultActionsConfig: ActionsConfig = {
1515
enabled: false,
1616
allowedHosts: [],
1717
enabledActionTypes: [],
18+
preconfigured: {},
19+
proxyRejectUnauthorizedCertificates: true,
20+
rejectUnauthorized: true,
1821
};
1922

2023
describe('ensureUriAllowed', () => {
2124
test('returns true when "any" hostnames are allowed', () => {
22-
const config: ActionsConfigType = {
25+
const config: ActionsConfig = {
26+
...defaultActionsConfig,
2327
enabled: false,
2428
allowedHosts: [AllowedHosts.Any],
2529
enabledActionTypes: [],
@@ -30,7 +34,7 @@ describe('ensureUriAllowed', () => {
3034
});
3135

3236
test('throws when the hostname in the requested uri is not in the allowedHosts', () => {
33-
const config: ActionsConfigType = DefaultActionsConfig;
37+
const config: ActionsConfig = defaultActionsConfig;
3438
expect(() =>
3539
getActionsConfigurationUtilities(config).ensureUriAllowed('https://github.com/elastic/kibana')
3640
).toThrowErrorMatchingInlineSnapshot(
@@ -39,7 +43,7 @@ describe('ensureUriAllowed', () => {
3943
});
4044

4145
test('throws when the uri cannot be parsed as a valid URI', () => {
42-
const config: ActionsConfigType = DefaultActionsConfig;
46+
const config: ActionsConfig = defaultActionsConfig;
4347
expect(() =>
4448
getActionsConfigurationUtilities(config).ensureUriAllowed('github.com/elastic')
4549
).toThrowErrorMatchingInlineSnapshot(
@@ -48,7 +52,8 @@ describe('ensureUriAllowed', () => {
4852
});
4953

5054
test('returns true when the hostname in the requested uri is in the allowedHosts', () => {
51-
const config: ActionsConfigType = {
55+
const config: ActionsConfig = {
56+
...defaultActionsConfig,
5257
enabled: false,
5358
allowedHosts: ['github.com'],
5459
enabledActionTypes: [],
@@ -61,7 +66,8 @@ describe('ensureUriAllowed', () => {
6166

6267
describe('ensureHostnameAllowed', () => {
6368
test('returns true when "any" hostnames are allowed', () => {
64-
const config: ActionsConfigType = {
69+
const config: ActionsConfig = {
70+
...defaultActionsConfig,
6571
enabled: false,
6672
allowedHosts: [AllowedHosts.Any],
6773
enabledActionTypes: [],
@@ -72,7 +78,7 @@ describe('ensureHostnameAllowed', () => {
7278
});
7379

7480
test('throws when the hostname in the requested uri is not in the allowedHosts', () => {
75-
const config: ActionsConfigType = DefaultActionsConfig;
81+
const config: ActionsConfig = defaultActionsConfig;
7682
expect(() =>
7783
getActionsConfigurationUtilities(config).ensureHostnameAllowed('github.com')
7884
).toThrowErrorMatchingInlineSnapshot(
@@ -81,7 +87,8 @@ describe('ensureHostnameAllowed', () => {
8187
});
8288

8389
test('returns true when the hostname in the requested uri is in the allowedHosts', () => {
84-
const config: ActionsConfigType = {
90+
const config: ActionsConfig = {
91+
...defaultActionsConfig,
8592
enabled: false,
8693
allowedHosts: ['github.com'],
8794
enabledActionTypes: [],
@@ -94,7 +101,8 @@ describe('ensureHostnameAllowed', () => {
94101

95102
describe('isUriAllowed', () => {
96103
test('returns true when "any" hostnames are allowed', () => {
97-
const config: ActionsConfigType = {
104+
const config: ActionsConfig = {
105+
...defaultActionsConfig,
98106
enabled: false,
99107
allowedHosts: [AllowedHosts.Any],
100108
enabledActionTypes: [],
@@ -105,21 +113,22 @@ describe('isUriAllowed', () => {
105113
});
106114

107115
test('throws when the hostname in the requested uri is not in the allowedHosts', () => {
108-
const config: ActionsConfigType = DefaultActionsConfig;
116+
const config: ActionsConfig = defaultActionsConfig;
109117
expect(
110118
getActionsConfigurationUtilities(config).isUriAllowed('https://github.com/elastic/kibana')
111119
).toEqual(false);
112120
});
113121

114122
test('throws when the uri cannot be parsed as a valid URI', () => {
115-
const config: ActionsConfigType = DefaultActionsConfig;
123+
const config: ActionsConfig = defaultActionsConfig;
116124
expect(getActionsConfigurationUtilities(config).isUriAllowed('github.com/elastic')).toEqual(
117125
false
118126
);
119127
});
120128

121129
test('returns true when the hostname in the requested uri is in the allowedHosts', () => {
122-
const config: ActionsConfigType = {
130+
const config: ActionsConfig = {
131+
...defaultActionsConfig,
123132
enabled: false,
124133
allowedHosts: ['github.com'],
125134
enabledActionTypes: [],
@@ -132,7 +141,8 @@ describe('isUriAllowed', () => {
132141

133142
describe('isHostnameAllowed', () => {
134143
test('returns true when "any" hostnames are allowed', () => {
135-
const config: ActionsConfigType = {
144+
const config: ActionsConfig = {
145+
...defaultActionsConfig,
136146
enabled: false,
137147
allowedHosts: [AllowedHosts.Any],
138148
enabledActionTypes: [],
@@ -141,12 +151,13 @@ describe('isHostnameAllowed', () => {
141151
});
142152

143153
test('throws when the hostname in the requested uri is not in the allowedHosts', () => {
144-
const config: ActionsConfigType = DefaultActionsConfig;
154+
const config: ActionsConfig = defaultActionsConfig;
145155
expect(getActionsConfigurationUtilities(config).isHostnameAllowed('github.com')).toEqual(false);
146156
});
147157

148158
test('returns true when the hostname in the requested uri is in the allowedHosts', () => {
149-
const config: ActionsConfigType = {
159+
const config: ActionsConfig = {
160+
...defaultActionsConfig,
150161
enabled: false,
151162
allowedHosts: ['github.com'],
152163
enabledActionTypes: [],
@@ -157,7 +168,8 @@ describe('isHostnameAllowed', () => {
157168

158169
describe('isActionTypeEnabled', () => {
159170
test('returns true when "any" actionTypes are allowed', () => {
160-
const config: ActionsConfigType = {
171+
const config: ActionsConfig = {
172+
...defaultActionsConfig,
161173
enabled: false,
162174
allowedHosts: [],
163175
enabledActionTypes: ['ignore', EnabledActionTypes.Any],
@@ -166,7 +178,8 @@ describe('isActionTypeEnabled', () => {
166178
});
167179

168180
test('returns false when no actionType is allowed', () => {
169-
const config: ActionsConfigType = {
181+
const config: ActionsConfig = {
182+
...defaultActionsConfig,
170183
enabled: false,
171184
allowedHosts: [],
172185
enabledActionTypes: [],
@@ -175,7 +188,8 @@ describe('isActionTypeEnabled', () => {
175188
});
176189

177190
test('returns false when the actionType is not in the enabled list', () => {
178-
const config: ActionsConfigType = {
191+
const config: ActionsConfig = {
192+
...defaultActionsConfig,
179193
enabled: false,
180194
allowedHosts: [],
181195
enabledActionTypes: ['foo'],
@@ -184,7 +198,8 @@ describe('isActionTypeEnabled', () => {
184198
});
185199

186200
test('returns true when the actionType is in the enabled list', () => {
187-
const config: ActionsConfigType = {
201+
const config: ActionsConfig = {
202+
...defaultActionsConfig,
188203
enabled: false,
189204
allowedHosts: [],
190205
enabledActionTypes: ['ignore', 'foo'],
@@ -195,7 +210,8 @@ describe('isActionTypeEnabled', () => {
195210

196211
describe('ensureActionTypeEnabled', () => {
197212
test('does not throw when any actionType is allowed', () => {
198-
const config: ActionsConfigType = {
213+
const config: ActionsConfig = {
214+
...defaultActionsConfig,
199215
enabled: false,
200216
allowedHosts: [],
201217
enabledActionTypes: ['ignore', EnabledActionTypes.Any],
@@ -204,7 +220,7 @@ describe('ensureActionTypeEnabled', () => {
204220
});
205221

206222
test('throws when no actionType is not allowed', () => {
207-
const config: ActionsConfigType = DefaultActionsConfig;
223+
const config: ActionsConfig = defaultActionsConfig;
208224
expect(() =>
209225
getActionsConfigurationUtilities(config).ensureActionTypeEnabled('foo')
210226
).toThrowErrorMatchingInlineSnapshot(
@@ -213,7 +229,8 @@ describe('ensureActionTypeEnabled', () => {
213229
});
214230

215231
test('throws when actionType is not enabled', () => {
216-
const config: ActionsConfigType = {
232+
const config: ActionsConfig = {
233+
...defaultActionsConfig,
217234
enabled: false,
218235
allowedHosts: [],
219236
enabledActionTypes: ['ignore'],
@@ -226,7 +243,8 @@ describe('ensureActionTypeEnabled', () => {
226243
});
227244

228245
test('does not throw when actionType is enabled', () => {
229-
const config: ActionsConfigType = {
246+
const config: ActionsConfig = {
247+
...defaultActionsConfig,
230248
enabled: false,
231249
allowedHosts: [],
232250
enabledActionTypes: ['ignore', 'foo'],

x-pack/plugins/actions/server/actions_config.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import url from 'url';
1010
import { curry } from 'lodash';
1111
import { pipe } from 'fp-ts/lib/pipeable';
1212

13-
import { ActionsConfigType } from './types';
13+
import { ActionsConfig } from './config';
1414
import { ActionTypeDisabledError } from './lib';
15+
import { ProxySettings } from './types';
1516

1617
export enum AllowedHosts {
1718
Any = '*',
@@ -33,6 +34,8 @@ export interface ActionsConfigurationUtilities {
3334
ensureHostnameAllowed: (hostname: string) => void;
3435
ensureUriAllowed: (uri: string) => void;
3536
ensureActionTypeEnabled: (actionType: string) => void;
37+
isRejectUnauthorizedCertificatesEnabled: () => boolean;
38+
getProxySettings: () => undefined | ProxySettings;
3639
}
3740

3841
function allowListErrorMessage(field: AllowListingField, value: string) {
@@ -56,14 +59,14 @@ function disabledActionTypeErrorMessage(actionType: string) {
5659
});
5760
}
5861

59-
function isAllowed({ allowedHosts }: ActionsConfigType, hostname: string | null): boolean {
62+
function isAllowed({ allowedHosts }: ActionsConfig, hostname: string | null): boolean {
6063
const allowed = new Set(allowedHosts);
6164
if (allowed.has(AllowedHosts.Any)) return true;
6265
if (hostname && allowed.has(hostname)) return true;
6366
return false;
6467
}
6568

66-
function isHostnameAllowedInUri(config: ActionsConfigType, uri: string): boolean {
69+
function isHostnameAllowedInUri(config: ActionsConfig, uri: string): boolean {
6770
return pipe(
6871
tryCatch(() => url.parse(uri)),
6972
map((parsedUrl) => parsedUrl.hostname),
@@ -73,7 +76,7 @@ function isHostnameAllowedInUri(config: ActionsConfigType, uri: string): boolean
7376
}
7477

7578
function isActionTypeEnabledInConfig(
76-
{ enabledActionTypes }: ActionsConfigType,
79+
{ enabledActionTypes }: ActionsConfig,
7780
actionType: string
7881
): boolean {
7982
const enabled = new Set(enabledActionTypes);
@@ -82,8 +85,20 @@ function isActionTypeEnabledInConfig(
8285
return false;
8386
}
8487

88+
function getProxySettingsFromConfig(config: ActionsConfig): undefined | ProxySettings {
89+
if (!config.proxyUrl) {
90+
return undefined;
91+
}
92+
93+
return {
94+
proxyUrl: config.proxyUrl,
95+
proxyHeaders: config.proxyHeaders,
96+
proxyRejectUnauthorizedCertificates: config.proxyRejectUnauthorizedCertificates,
97+
};
98+
}
99+
85100
export function getActionsConfigurationUtilities(
86-
config: ActionsConfigType
101+
config: ActionsConfig
87102
): ActionsConfigurationUtilities {
88103
const isHostnameAllowed = curry(isAllowed)(config);
89104
const isUriAllowed = curry(isHostnameAllowedInUri)(config);
@@ -92,6 +107,8 @@ export function getActionsConfigurationUtilities(
92107
isHostnameAllowed,
93108
isUriAllowed,
94109
isActionTypeEnabled,
110+
getProxySettings: () => getProxySettingsFromConfig(config),
111+
isRejectUnauthorizedCertificatesEnabled: () => config.rejectUnauthorized,
95112
ensureUriAllowed(uri: string) {
96113
if (!isUriAllowed(uri)) {
97114
throw new Error(allowListErrorMessage(AllowListingField.URL, uri));

x-pack/plugins/actions/server/builtin_action_types/email.test.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,16 @@ describe('execute()', () => {
277277
`);
278278
expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(`
279279
Object {
280+
"configurationUtilities": Object {
281+
"ensureActionTypeEnabled": [MockFunction],
282+
"ensureHostnameAllowed": [MockFunction],
283+
"ensureUriAllowed": [MockFunction],
284+
"getProxySettings": [MockFunction],
285+
"isActionTypeEnabled": [MockFunction],
286+
"isHostnameAllowed": [MockFunction],
287+
"isRejectUnauthorizedCertificatesEnabled": [MockFunction],
288+
"isUriAllowed": [MockFunction],
289+
},
280290
"content": Object {
281291
"message": "a message to you
282292
@@ -286,7 +296,6 @@ describe('execute()', () => {
286296
"subject": "the subject",
287297
},
288298
"hasAuth": true,
289-
"proxySettings": undefined,
290299
"routing": Object {
291300
"bcc": Array [
292301
"jimmy@example.com",
@@ -327,6 +336,16 @@ describe('execute()', () => {
327336
await actionType.executor(customExecutorOptions);
328337
expect(sendEmailMock.mock.calls[0][1]).toMatchInlineSnapshot(`
329338
Object {
339+
"configurationUtilities": Object {
340+
"ensureActionTypeEnabled": [MockFunction],
341+
"ensureHostnameAllowed": [MockFunction],
342+
"ensureUriAllowed": [MockFunction],
343+
"getProxySettings": [MockFunction],
344+
"isActionTypeEnabled": [MockFunction],
345+
"isHostnameAllowed": [MockFunction],
346+
"isRejectUnauthorizedCertificatesEnabled": [MockFunction],
347+
"isUriAllowed": [MockFunction],
348+
},
330349
"content": Object {
331350
"message": "a message to you
332351
@@ -336,7 +355,6 @@ describe('execute()', () => {
336355
"subject": "the subject",
337356
},
338357
"hasAuth": false,
339-
"proxySettings": undefined,
340358
"routing": Object {
341359
"bcc": Array [
342360
"jimmy@example.com",

0 commit comments

Comments
 (0)