From c52339e60621951832d1c0cf90f8b0dab373f4ae Mon Sep 17 00:00:00 2001 From: John Schulz Date: Tue, 19 Jan 2021 07:24:11 -0500 Subject: [PATCH] [Fleet][EPM] If proxy url has username & password, add to Node's Agent options (#86807) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary A user received a `407` response when using a `registryProxyUrl` format like `http://user:pass@host:port` I believe the issue is we're not including the [`auth` property as described in this issue](https://github.com/TooTallNate/node-https-proxy-agent/issues/12#issuecomment-216098644). Add tests to ensure it only adds `auth` if username & password are given. ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ``` getProxyAgentOptions auth property present & correct if given username and password ✓ proxy url is http (1 ms) ✓ proxy url is https missing if not given username and password ✓ proxy url is http ✓ proxy url is https ``` --- .../services/epm/registry/proxy.test.ts | 61 +++++++++++++++++++ .../server/services/epm/registry/proxy.ts | 4 ++ 2 files changed, 65 insertions(+) diff --git a/x-pack/plugins/fleet/server/services/epm/registry/proxy.test.ts b/x-pack/plugins/fleet/server/services/epm/registry/proxy.test.ts index d6e60eb11b23..1d888bef69ee 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/proxy.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/proxy.test.ts @@ -67,4 +67,65 @@ describe('getProxyAgentOptions', () => { rejectUnauthorized: undefined, }); }); + describe('auth property', () => { + describe('present & correct if given username and password', () => { + test('proxy url is http', () => { + const httpProxyWithAuth = { + proxyUrl: 'http://user:pass@example.com:8080/p/a/t/h', + targetUrl: 'https://epr.elastic.co/', + }; + expect(getProxyAgentOptions(httpProxyWithAuth)).toEqual({ + auth: 'user:pass', + headers: { Host: 'epr.elastic.co' }, + host: 'example.com', + port: 8080, + protocol: 'http:', + rejectUnauthorized: undefined, + }); + }); + test('proxy url is https', () => { + const httpsProxyWithAuth = { + proxyUrl: 'https://user:pass@example.com:8080/p/a/t/h', + targetUrl: 'https://epr.elastic.co/', + }; + expect(getProxyAgentOptions(httpsProxyWithAuth)).toEqual({ + auth: 'user:pass', + headers: { Host: 'epr.elastic.co' }, + host: 'example.com', + port: 8080, + protocol: 'https:', + rejectUnauthorized: undefined, + }); + }); + }); + + describe('missing if not given username and password', () => { + test('proxy url is http', () => { + const httpProxyWithout = { + proxyUrl: 'http://example.com:8080/p/a/t/h', + targetUrl: 'https://epr.elastic.co/', + }; + expect(getProxyAgentOptions(httpProxyWithout)).toEqual({ + headers: { Host: 'epr.elastic.co' }, + host: 'example.com', + port: 8080, + protocol: 'http:', + rejectUnauthorized: undefined, + }); + }); + test('proxy url is https', () => { + const httpsProxyWithoutAuth = { + proxyUrl: 'https://example.com:8080/p/a/t/h', + targetUrl: 'https://epr.elastic.co/', + }; + expect(getProxyAgentOptions(httpsProxyWithoutAuth)).toEqual({ + headers: { Host: 'epr.elastic.co' }, + host: 'example.com', + port: 8080, + protocol: 'https:', + rejectUnauthorized: undefined, + }); + }); + }); + }); }); diff --git a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts index ae1c13761052..97be49d83c0a 100644 --- a/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts +++ b/x-pack/plugins/fleet/server/services/epm/registry/proxy.ts @@ -38,11 +38,15 @@ export function getProxyAgent(options: GetProxyAgentParams): ProxyAgent { export function getProxyAgentOptions(options: GetProxyAgentParams): HttpsProxyAgentOptions { const endpointParsed = new URL(options.targetUrl); const proxyParsed = new URL(options.proxyUrl); + const authValue = proxyParsed.username + ? `${proxyParsed.username}:${proxyParsed.password}` + : undefined; return { host: proxyParsed.hostname, port: Number(proxyParsed.port), protocol: proxyParsed.protocol, + auth: authValue, // The headers to send headers: options.proxyHeaders || { // the proxied URL's host is put in the header instead of the server's actual host