From 4c258e27b65d6dd4810a5225fcbf9c8f8f31c1db Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 4 Feb 2020 11:14:31 -0800 Subject: [PATCH] =?UTF-8?q?fix:=20Remove=20authorization=20header=20from?= =?UTF-8?q?=20core.windows.net=20requests=E2=80=A6=20(#5274)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/datasource/docker/index.ts | 50 ++++++++++++-------- test/datasource/docker.spec.ts | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 20 deletions(-) diff --git a/lib/datasource/docker/index.ts b/lib/datasource/docker/index.ts index bf0da769de481e..28c5e04be73db4 100644 --- a/lib/datasource/docker/index.ts +++ b/lib/datasource/docker/index.ts @@ -1,3 +1,7 @@ +/** + * @copyright 2020-present by Avid Technology, Inc. + */ + import is from '@sindresorhus/is'; import hasha from 'hasha'; import URL from 'url'; @@ -420,6 +424,31 @@ async function getTags( } } +export function getConfigResponseBeforeRedirectHook(options: any): void { + if (options.search?.includes('X-Amz-Algorithm')) { + // if there is no port in the redirect URL string, then delete it from the redirect options. + // This can be evaluated for removal after upgrading to Got v10 + const portInUrl = options.href.split('/')[2].split(':')[1]; + if (!portInUrl) { + // eslint-disable-next-line no-param-reassign + delete options.port; // Redirect will instead use 80 or 443 for HTTP or HTTPS respectively + } + + // docker registry is hosted on amazon, redirect url includes authentication. + // eslint-disable-next-line no-param-reassign + delete options.headers.authorization; + } + + if ( + options.href?.includes('blob.core.windows.net') && + options.headers?.authorization + ) { + // docker registry is hosted on Azure blob, redirect url includes authentication. + // eslint-disable-next-line no-param-reassign + delete options.headers.authorization; + } +} + export function getConfigResponse( url: string, headers: OutgoingHttpHeaders @@ -427,26 +456,7 @@ export function getConfigResponse( return got(url, { headers, hooks: { - beforeRedirect: [ - (options: any): void => { - if ( - options.search && - options.search.indexOf('X-Amz-Algorithm') !== -1 - ) { - // if there is no port in the redirect URL string, then delete it from the redirect options. - // This can be evaluated for removal after upgrading to Got v10 - const portInUrl = options.href.split('/')[2].split(':')[1]; - if (!portInUrl) { - // eslint-disable-next-line no-param-reassign - delete options.port; // Redirect will instead use 80 or 443 for HTTP or HTTPS respectively - } - - // docker registry is hosted on amazon, redirect url includes authentication. - // eslint-disable-next-line no-param-reassign - delete options.headers.authorization; - } - }, - ], + beforeRedirect: [getConfigResponseBeforeRedirectHook], }, }); } diff --git a/test/datasource/docker.spec.ts b/test/datasource/docker.spec.ts index fb80944223a478..1c1f5d490938e1 100644 --- a/test/datasource/docker.spec.ts +++ b/test/datasource/docker.spec.ts @@ -411,4 +411,88 @@ describe('api/docker', () => { expect(res).toBeNull(); }); }); + describe('getConfigResponseBeforeRedirectHook', () => { + it('leaves a non-Amazon or Microsoft request unmodified', () => { + const emptyOpts = {}; + docker.getConfigResponseBeforeRedirectHook(emptyOpts); + expect(emptyOpts).toEqual({}); + + const nonAmzOpts = { + search: 'my-search-string', + }; + docker.getConfigResponseBeforeRedirectHook(nonAmzOpts); + expect(nonAmzOpts).toEqual({ + search: 'my-search-string', + }); + + const nonMsOpts = { + href: 'https://myurl.com', + }; + docker.getConfigResponseBeforeRedirectHook(nonMsOpts); + expect(nonMsOpts).toEqual({ + href: 'https://myurl.com', + }); + }); + + it('removes the authorization header for Azure requests', () => { + const href = 'https://myaccount.blob.core.windows.net/xyz'; + const opts = { + href, + }; + docker.getConfigResponseBeforeRedirectHook(opts); + expect(opts).toEqual({ href }); + + const optsWithHeadersNoAuth = { + href, + headers: {}, + }; + docker.getConfigResponseBeforeRedirectHook(opts); + expect(optsWithHeadersNoAuth).toEqual({ + href, + headers: {}, + }); + + const optsWithAuth = { + href, + headers: { + authorization: 'Bearer xyz', + }, + }; + docker.getConfigResponseBeforeRedirectHook(optsWithAuth); + expect(optsWithAuth.headers).toBeDefined(); + expect(optsWithAuth.headers.authorization).not.toBeDefined(); + }); + + it('removes the authorization header for Amazon requests', () => { + const href = 'https://amazon.com'; + const search = 'X-Amz-Algorithm'; + const authorization = 'Bearer xyz'; + const opts = { + href, + search, + headers: { + authorization, + }, + }; + docker.getConfigResponseBeforeRedirectHook(opts); + expect(opts).toEqual({ search, href, headers: {} }); + }); + + it('removes the port when not specified in URL', () => { + const href = 'https://amazon.com/xyz'; + const search = 'X-Amz-Algorithm'; + const authorization = 'Bearer xyz'; + const port = 8080; + const opts = { + href, + search, + port, + headers: { + authorization, + }, + }; + docker.getConfigResponseBeforeRedirectHook(opts); + expect(opts).toEqual({ search, href, headers: {} }); + }); + }); });