-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[7.8] Support deep links inside of
RelayState
for SAML IdP initiate…
…d login. (#69774) # Conflicts: # x-pack/plugins/security/server/authentication/providers/saml.test.ts # x-pack/plugins/security/server/authentication/providers/saml.ts # x-pack/plugins/security/server/routes/authentication/saml.ts
- Loading branch information
Showing
12 changed files
with
604 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { isInternalURL } from './is_internal_url'; | ||
|
||
describe('isInternalURL', () => { | ||
describe('with basePath defined', () => { | ||
const basePath = '/iqf'; | ||
|
||
it('should return `true `if URL includes hash fragment', () => { | ||
const href = `${basePath}/app/kibana#/discover/New-Saved-Search`; | ||
expect(isInternalURL(href, basePath)).toBe(true); | ||
}); | ||
|
||
it('should return `false` if URL includes a protocol/hostname', () => { | ||
const href = `https://example.com${basePath}/app/kibana`; | ||
expect(isInternalURL(href, basePath)).toBe(false); | ||
}); | ||
|
||
it('should return `false` if URL includes a port', () => { | ||
const href = `http://localhost:5601${basePath}/app/kibana`; | ||
expect(isInternalURL(href, basePath)).toBe(false); | ||
}); | ||
|
||
it('should return `false` if URL does not specify protocol', () => { | ||
const hrefWithTwoSlashes = `/${basePath}/app/kibana`; | ||
expect(isInternalURL(hrefWithTwoSlashes)).toBe(false); | ||
|
||
const hrefWithThreeSlashes = `//${basePath}/app/kibana`; | ||
expect(isInternalURL(hrefWithThreeSlashes)).toBe(false); | ||
}); | ||
|
||
it('should return `true` if URL starts with a basepath', () => { | ||
for (const href of [basePath, `${basePath}/`, `${basePath}/login`, `${basePath}/login/`]) { | ||
expect(isInternalURL(href, basePath)).toBe(true); | ||
} | ||
}); | ||
|
||
it('should return `false` if URL does not start with basePath', () => { | ||
for (const href of [ | ||
'/notbasepath/app/kibana', | ||
`${basePath}_/login`, | ||
basePath.slice(1), | ||
`${basePath.slice(1)}/app/kibana`, | ||
]) { | ||
expect(isInternalURL(href, basePath)).toBe(false); | ||
} | ||
}); | ||
|
||
it('should return `true` if relative path does not escape base path', () => { | ||
const href = `${basePath}/app/kibana/../../management`; | ||
expect(isInternalURL(href, basePath)).toBe(true); | ||
}); | ||
|
||
it('should return `false` if relative path escapes base path', () => { | ||
const href = `${basePath}/app/kibana/../../../management`; | ||
expect(isInternalURL(href, basePath)).toBe(false); | ||
}); | ||
}); | ||
|
||
describe('without basePath defined', () => { | ||
it('should return `true `if URL includes hash fragment', () => { | ||
const href = '/app/kibana#/discover/New-Saved-Search'; | ||
expect(isInternalURL(href)).toBe(true); | ||
}); | ||
|
||
it('should return `false` if URL includes a protocol/hostname', () => { | ||
const href = 'https://example.com/app/kibana'; | ||
expect(isInternalURL(href)).toBe(false); | ||
}); | ||
|
||
it('should return `false` if URL includes a port', () => { | ||
const href = 'http://localhost:5601/app/kibana'; | ||
expect(isInternalURL(href)).toBe(false); | ||
}); | ||
|
||
it('should return `false` if URL does not specify protocol', () => { | ||
const hrefWithTwoSlashes = `//app/kibana`; | ||
expect(isInternalURL(hrefWithTwoSlashes)).toBe(false); | ||
|
||
const hrefWithThreeSlashes = `///app/kibana`; | ||
expect(isInternalURL(hrefWithThreeSlashes)).toBe(false); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { parse } from 'url'; | ||
|
||
export function isInternalURL(url: string, basePath = '') { | ||
const { protocol, hostname, port, pathname } = parse( | ||
url, | ||
false /* parseQueryString */, | ||
true /* slashesDenoteHost */ | ||
); | ||
|
||
// We should explicitly compare `protocol`, `port` and `hostname` to null to make sure these are not | ||
// detected in the URL at all. For example `hostname` can be empty string for Node URL parser, but | ||
// browser (because of various bwc reasons) processes URL differently (e.g. `///abc.com` - for browser | ||
// hostname is `abc.com`, but for Node hostname is an empty string i.e. everything between schema (`//`) | ||
// and the first slash that belongs to path. | ||
if (protocol !== null || hostname !== null || port !== null) { | ||
return false; | ||
} | ||
|
||
if (basePath) { | ||
// Now we need to normalize URL to make sure any relative path segments (`..`) cannot escape expected | ||
// base path. We can rely on `URL` with a localhost to automatically "normalize" the URL. | ||
const normalizedPathname = new URL(String(pathname), 'https://localhost').pathname; | ||
return ( | ||
// Normalized pathname can add a leading slash, but we should also make sure it's included in | ||
// the original URL too | ||
pathname?.startsWith('/') && | ||
(normalizedPathname === basePath || normalizedPathname.startsWith(`${basePath}/`)) | ||
); | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.