Skip to content

Commit

Permalink
fix relative urls in external url service (#116404)
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Nov 2, 2021
1 parent b03a869 commit 14c0d35
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 4 deletions.
58 changes: 57 additions & 1 deletion src/core/public/http/external_url_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,40 @@ describe('External Url Service', () => {
});
});

internalRequestScenarios.forEach(({ description, policy, allowExternal }) => {
describe(description, () => {
it('allows relative URLs without absolute path replacing last path segment', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `my_other_app?foo=bar`;
const result = setup.validateUrl(urlCandidate);

expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}/app/${urlCandidate}`);
});

it('allows relative URLs without absolute path replacing multiple path segments', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/api/my_other_app?foo=bar`;
const result = setup.validateUrl(`..${urlCandidate}`);

expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}${urlCandidate}`);
});

if (!allowExternal) {
describe('handles bypass of base path via relative URL', () => {
it('does not allow relative URLs that escape base path', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });
const urlCandidate = `../../base_path_escape`;
const result = setup.validateUrl(urlCandidate);

expect(result).toBeNull();
});
});
}
});
});

describe('handles protocol resolution bypass', () => {
it('does not allow relative URLs that include a host', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });
Expand Down Expand Up @@ -194,7 +228,7 @@ describe('External Url Service', () => {

internalRequestScenarios.forEach(({ description, policy }) => {
describe(description, () => {
it('allows relative URLs', () => {
it('allows relative URLs with absolute path', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/some/path?foo=bar`;
const result = setup.validateUrl(`${serverBasePath}${urlCandidate}`);
Expand All @@ -214,6 +248,28 @@ describe('External Url Service', () => {
});
});

internalRequestScenarios.forEach(({ description, policy }) => {
describe(description, () => {
it('allows relative URLs without absolute path replacing last path segment', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `my_other_app?foo=bar`;
const result = setup.validateUrl(urlCandidate);

expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}/app/${urlCandidate}`);
});

it('allows relative URLs without absolute path replacing multiple path segments', () => {
const { setup } = setupService({ location, serverBasePath, policy });
const urlCandidate = `/api/my_other_app?foo=bar`;
const result = setup.validateUrl(`..${urlCandidate}`);

expect(result).toBeInstanceOf(URL);
expect(result?.toString()).toEqual(`${kibanaRoot}${urlCandidate}`);
});
});
});

describe('handles protocol resolution bypass', () => {
it('does not allow relative URLs that include a host', () => {
const { setup } = setupService({ location, serverBasePath, policy: [] });
Expand Down
6 changes: 3 additions & 3 deletions src/core/public/http/external_url_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { InjectedMetadataSetup } from '../injected_metadata';
import { Sha256 } from '../utils';

interface SetupDeps {
location: Pick<Location, 'origin'>;
location: Pick<Location, 'href'>;
injectedMetadata: InjectedMetadataSetup;
}

Expand Down Expand Up @@ -52,11 +52,11 @@ function normalizeProtocol(protocol: string) {

const createExternalUrlValidation = (
rules: IExternalUrlPolicy[],
location: Pick<Location, 'origin'>,
location: Pick<Location, 'href'>,
serverBasePath: string
) => {
const base = new URL(location.origin + serverBasePath);
return function validateExternalUrl(next: string) {
const base = new URL(location.href);
const url = new URL(next, base);

const isInternalURL =
Expand Down

0 comments on commit 14c0d35

Please sign in to comment.