From 20276bd84da6656b671a8f5e2b403f79344f7bc9 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Thu, 29 Oct 2020 18:41:37 +0100 Subject: [PATCH] [7.x] Update KibanaRequest to use the new WHATWG URL API (#80713) (#82014) --- ...kibana-plugin-core-server.kibanarequest.md | 4 +-- ...-core-server.kibanarequest.rewrittenurl.md | 2 +- ...na-plugin-core-server.kibanarequest.url.md | 2 +- src/core/server/http/http_server.mocks.ts | 28 +++++++++++-------- src/core/server/http/http_server.ts | 2 +- .../http/integration_tests/lifecycle.test.ts | 24 ++++++++++++++-- .../server/http/lifecycle/on_pre_routing.ts | 25 +++++++++++++++-- src/core/server/http/router/request.ts | 15 +++++----- src/core/server/server.api.md | 6 ++-- .../server/lib/task_runner_factory.test.ts | 18 ++++++++++++ .../actions/server/lib/task_runner_factory.ts | 6 ++++ .../server/alerts_client_factory.test.ts | 6 ++++ x-pack/plugins/alerts/server/plugin.test.ts | 6 ++++ .../server/task_runner/task_runner.test.ts | 18 ++++++++++++ .../alerts/server/task_runner/task_runner.ts | 6 ++++ ...dashboard_mode_request_interceptor.test.ts | 10 +++---- .../dashboard_mode_request_interceptor.ts | 2 +- .../lib/enterprise_search_config_api.test.ts | 1 - .../event_log/server/event_log_client.test.ts | 6 ++++ .../server/event_log_start_service.test.ts | 6 ++++ .../saved_object_provider_registry.test.ts | 6 ++++ .../server/services/agent_policy_update.ts | 6 ++++ .../agents/checkin/state_connected_agents.ts | 6 ++++ .../agents/checkin/state_new_actions.ts | 6 ++++ .../ml/server/routes/data_frame_analytics.ts | 12 ++------ x-pack/plugins/reporting/server/core.ts | 7 +++++ .../plugins/reporting/server/routes/legacy.ts | 2 +- .../lib/authorized_user_pre_routing.test.ts | 2 +- .../server/audit/audit_events.test.ts | 16 ++++------- .../security/server/audit/audit_events.ts | 14 +++++----- .../server/authentication/authenticator.ts | 4 +-- .../authentication/providers/basic.test.ts | 4 +-- .../server/authentication/providers/basic.ts | 10 +++++-- .../server/authentication/providers/http.ts | 8 ++++-- .../authentication/providers/kerberos.ts | 6 ++-- .../server/authentication/providers/oidc.ts | 8 ++++-- .../server/authentication/providers/pki.ts | 6 ++-- .../server/authentication/providers/saml.ts | 8 ++++-- .../authentication/providers/token.test.ts | 4 +-- .../server/authentication/providers/token.ts | 10 +++++-- .../server/authorization/api_authorization.ts | 6 ++-- .../authorization/authorization_service.tsx | 2 +- .../server/routes/authentication/oidc.ts | 2 +- .../server/routes/views/login.test.ts | 4 +-- .../on_post_auth_interceptor.ts | 2 +- .../on_request_interceptor.ts | 13 ++------- .../spaces_service/spaces_service.test.ts | 10 +++---- 47 files changed, 263 insertions(+), 114 deletions(-) diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.md b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.md index 1134994faa9bd3..4129662acb2b1d 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.md @@ -30,9 +30,9 @@ export declare class KibanaRequestboolean | Whether or not the request is a "system request" rather than an application-level request. Can be set on the client using the HttpFetchOptions#asSystemRequest option. | | [params](./kibana-plugin-core-server.kibanarequest.params.md) | | Params | | | [query](./kibana-plugin-core-server.kibanarequest.query.md) | | Query | | -| [rewrittenUrl](./kibana-plugin-core-server.kibanarequest.rewrittenurl.md) | | Url | URL rewritten in onPreRouting request interceptor. | +| [rewrittenUrl](./kibana-plugin-core-server.kibanarequest.rewrittenurl.md) | | URL | URL rewritten in onPreRouting request interceptor. | | [route](./kibana-plugin-core-server.kibanarequest.route.md) | | RecursiveReadonly<KibanaRequestRoute<Method>> | matched route details | | [socket](./kibana-plugin-core-server.kibanarequest.socket.md) | | IKibanaSocket | [IKibanaSocket](./kibana-plugin-core-server.ikibanasocket.md) | -| [url](./kibana-plugin-core-server.kibanarequest.url.md) | | Url | a WHATWG URL standard object. | +| [url](./kibana-plugin-core-server.kibanarequest.url.md) | | URL | a WHATWG URL standard object. | | [uuid](./kibana-plugin-core-server.kibanarequest.uuid.md) | | string | A UUID to identify this request. | diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md index 10628bafaf1d41..fb547330ee6ea1 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.rewrittenurl.md @@ -9,5 +9,5 @@ URL rewritten in onPreRouting request interceptor. Signature: ```typescript -readonly rewrittenUrl?: Url; +readonly rewrittenUrl?: URL; ``` diff --git a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md index 31d13481972017..b72760e272bb21 100644 --- a/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md +++ b/docs/development/core/server/kibana-plugin-core-server.kibanarequest.url.md @@ -9,5 +9,5 @@ a WHATWG URL standard object. Signature: ```typescript -readonly url: Url; +readonly url: URL; ``` diff --git a/src/core/server/http/http_server.mocks.ts b/src/core/server/http/http_server.mocks.ts index 6aad232cf42b64..d615e799f383f0 100644 --- a/src/core/server/http/http_server.mocks.ts +++ b/src/core/server/http/http_server.mocks.ts @@ -16,6 +16,7 @@ * specific language governing permissions and limitations * under the License. */ +import { parse as parseUrl } from 'url'; import { Request } from 'hapi'; import { merge } from 'lodash'; import { Socket } from 'net'; @@ -72,6 +73,7 @@ function createKibanaRequestMock

({ auth = { isAuthenticated: true }, }: RequestFixtureOptions = {}) { const queryString = stringify(query, { sort: false }); + const url = parseUrl(`${path}${queryString ? `?${queryString}` : ''}`); return KibanaRequest.from( createRawRequestMock({ @@ -83,12 +85,7 @@ function createKibanaRequestMock

({ payload: body, path, method, - url: { - path, - pathname: path, - query: queryString, - search: queryString ? `?${queryString}` : queryString, - }, + url, route: { settings: { tags: routeTags, auth: routeAuthRequired, app: kibanaRouteOptions }, }, @@ -121,6 +118,11 @@ interface DeepPartialArray extends Array> {} type DeepPartialObject = { [P in keyof T]+?: DeepPartial }; function createRawRequestMock(customization: DeepPartial = {}) { + const pathname = customization.url?.pathname || '/'; + const path = `${pathname}${customization.url?.search || ''}`; + const url = Object.assign({ pathname, path, href: path }, customization.url); + + // @ts-expect-error _core isn't supposed to be accessed - remove once we upgrade to hapi v18 return merge( {}, { @@ -129,17 +131,21 @@ function createRawRequestMock(customization: DeepPartial = {}) { isAuthenticated: true, }, headers: {}, - path: '/', + path, route: { settings: {} }, - url: { - href: '/', - }, + url, raw: { req: { - url: '/', + url: path, socket: {}, }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }, customization ) as Request; diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index 2440f2b1da0bd2..d94bce12fb4397 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -271,7 +271,7 @@ export class HttpServer { } this.registerOnPreRouting((request, response, toolkit) => { - const oldUrl = request.url.href!; + const oldUrl = request.url.pathname + request.url.search; const newURL = basePathService.remove(oldUrl); const shouldRedirect = newURL !== oldUrl; if (shouldRedirect) { diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts index 01817b29de8ac1..37401a2c24ccd1 100644 --- a/src/core/server/http/integration_tests/lifecycle.test.ts +++ b/src/core/server/http/integration_tests/lifecycle.test.ts @@ -124,7 +124,13 @@ describe('OnPreRouting', () => { const router = createRouter('/'); router.get({ path: '/login', validate: false }, (context, req, res) => { - return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } }); + return res.ok({ + body: { + rewrittenUrl: req.rewrittenUrl + ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}` + : undefined, + }, + }); }); registerOnPreRouting((req, res, t) => t.rewriteUrl('/login')); @@ -143,7 +149,13 @@ describe('OnPreRouting', () => { const router = createRouter('/'); router.get({ path: '/reroute-2', validate: false }, (context, req, res) => { - return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } }); + return res.ok({ + body: { + rewrittenUrl: req.rewrittenUrl + ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}` + : undefined, + }, + }); }); registerOnPreRouting((req, res, t) => t.rewriteUrl('/reroute-1')); @@ -163,7 +175,13 @@ describe('OnPreRouting', () => { const router = createRouter('/'); router.get({ path: '/login', validate: false }, (context, req, res) => { - return res.ok({ body: { rewrittenUrl: req.rewrittenUrl?.path } }); + return res.ok({ + body: { + rewrittenUrl: req.rewrittenUrl + ? `${req.rewrittenUrl.pathname}${req.rewrittenUrl.search}` + : undefined, + }, + }); }); registerOnPreRouting((req, res, t) => t.next()); diff --git a/src/core/server/http/lifecycle/on_pre_routing.ts b/src/core/server/http/lifecycle/on_pre_routing.ts index 92ae1f0b7bbdfe..e553f113a7cf8d 100644 --- a/src/core/server/http/lifecycle/on_pre_routing.ts +++ b/src/core/server/http/lifecycle/on_pre_routing.ts @@ -17,6 +17,7 @@ * under the License. */ +import { URL } from 'url'; import { Lifecycle, Request, ResponseToolkit as HapiResponseToolkit } from 'hapi'; import { Logger } from '../../logging'; import { @@ -110,10 +111,30 @@ export function adoptToHapiOnRequest(fn: OnPreRoutingHandler, log: Logger) { if (preRoutingResult.isRewriteUrl(result)) { const appState = request.app as KibanaRequestState; - appState.rewrittenUrl = appState.rewrittenUrl ?? request.url; + appState.rewrittenUrl = + // @ts-expect-error request._core isn't supposed to be accessed - remove once we upgrade to hapi v18 + appState.rewrittenUrl ?? new URL(request.url.href!, request._core.info.uri); const { url } = result; - request.setUrl(url); + + // TODO: Remove once we upgrade to Node.js 12! + // + // Warning: The following for-loop took 10 days to write, and is a hack + // to force V8 to make a copy of the string in memory. + // + // The reason why we need this is because of what appears to be a bug + // in V8 that caused some URL paths to not be routed correctly once + // `request.setUrl` was called with the path. + // + // The details can be seen in this discussion on Twitter: + // https://twitter.com/wa7son/status/1319992632366518277 + let urlCopy = ''; + for (let i = 0; i < url.length; i++) { + urlCopy += url[i]; + } + + request.setUrl(urlCopy); + // We should update raw request as well since it can be proxied to the old platform request.raw.req.url = url; return responseToolkit.continue; diff --git a/src/core/server/http/router/request.ts b/src/core/server/http/router/request.ts index 2d0e8d6c1a6ad9..561bf742050c34 100644 --- a/src/core/server/http/router/request.ts +++ b/src/core/server/http/router/request.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Url } from 'url'; +import { URL } from 'url'; import uuid from 'uuid'; import { Request, RouteOptionsApp, ApplicationState } from 'hapi'; import { Observable, fromEvent, merge } from 'rxjs'; @@ -45,7 +45,7 @@ export interface KibanaRouteOptions extends RouteOptionsApp { export interface KibanaRequestState extends ApplicationState { requestId: string; requestUuid: string; - rewrittenUrl?: Url; + rewrittenUrl?: URL; } /** @@ -163,7 +163,7 @@ export class KibanaRequest< */ public readonly uuid: string; /** a WHATWG URL standard object. */ - public readonly url: Url; + public readonly url: URL; /** matched route details */ public readonly route: RecursiveReadonly>; /** @@ -190,7 +190,7 @@ export class KibanaRequest< /** * URL rewritten in onPreRouting request interceptor. */ - public readonly rewrittenUrl?: Url; + public readonly rewrittenUrl?: URL; /** @internal */ protected readonly [requestSymbol]: Request; @@ -212,7 +212,8 @@ export class KibanaRequest< this.uuid = appState?.requestUuid ?? uuid.v4(); this.rewrittenUrl = appState?.rewrittenUrl; - this.url = request.url; + // @ts-expect-error request._core isn't supposed to be accessed - remove once we upgrade to hapi v18 + this.url = new URL(request.url.href!, request._core.info.uri); this.headers = deepFreeze({ ...request.headers }); this.isSystemRequest = request.headers['kbn-system-request'] === 'true' || @@ -304,8 +305,8 @@ export class KibanaRequest< if (authOptions === false) return false; throw new Error( `unexpected authentication options: ${JSON.stringify(authOptions)} for route: ${ - this.url.href - }` + this.url.pathname + }${this.url.search}` ); } } diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index d9dc46d2cad997..914b5fbdb5196f 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -162,7 +162,7 @@ import { Type } from '@kbn/config-schema'; import { TypeOf } from '@kbn/config-schema'; import { UpdateDocumentByQueryParams } from 'elasticsearch'; import { UpdateDocumentParams } from 'elasticsearch'; -import { Url } from 'url'; +import { URL } from 'url'; // @public export interface AppCategory { @@ -1007,11 +1007,11 @@ export class KibanaRequest>; // (undocumented) readonly socket: IKibanaSocket; - readonly url: Url; + readonly url: URL; readonly uuid: string; } diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index 18cbd9f9c5fada..c8e26846515980 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -145,6 +145,12 @@ test('executes the task by calling the executor with proper parameters', async ( url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }, }); }); @@ -271,6 +277,12 @@ test('uses API key when provided', async () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }, }); }); @@ -310,6 +322,12 @@ test(`doesn't use API key when not provided`, async () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }, }); }); diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index aeeeb4ed7d520d..93ae5a2c807f9c 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -102,6 +102,12 @@ export class TaskRunnerFactory { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, } as unknown) as KibanaRequest; let executorResult: ActionTypeExecutorResult; diff --git a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts index 55c2f3ddd18a41..4e457cdb12bd39 100644 --- a/x-pack/plugins/alerts/server/alerts_client_factory.test.ts +++ b/x-pack/plugins/alerts/server/alerts_client_factory.test.ts @@ -60,6 +60,12 @@ const fakeRequest = ({ url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, getSavedObjectsClient: () => savedObjectsClient, } as unknown) as Request; diff --git a/x-pack/plugins/alerts/server/plugin.test.ts b/x-pack/plugins/alerts/server/plugin.test.ts index b13a1c62f66022..ece7d31d2f7fdc 100644 --- a/x-pack/plugins/alerts/server/plugin.test.ts +++ b/x-pack/plugins/alerts/server/plugin.test.ts @@ -149,6 +149,12 @@ describe('Alerting Plugin', () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, getSavedObjectsClient: jest.fn(), } as unknown) as KibanaRequest; await startContract.getAlertsClientWithRequest(fakeRequest); diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts index 8e345d6ff66a8a..17d5fcd31b745c 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.test.ts @@ -364,6 +364,12 @@ describe('Task Runner', () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }); expect(actionsClient.enqueueExecution).toHaveBeenCalledTimes(1); expect(actionsClient.enqueueExecution.mock.calls[0]).toMatchInlineSnapshot(` @@ -662,6 +668,12 @@ describe('Task Runner', () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }); }); @@ -694,6 +706,12 @@ describe('Task Runner', () => { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, }); }); diff --git a/x-pack/plugins/alerts/server/task_runner/task_runner.ts b/x-pack/plugins/alerts/server/task_runner/task_runner.ts index 954c5675df89c9..76125da20d552f 100644 --- a/x-pack/plugins/alerts/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerts/server/task_runner/task_runner.ts @@ -101,6 +101,12 @@ export class TaskRunner { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, } as unknown) as KibanaRequest; } diff --git a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts index 67fc1a98ad4d1f..4b1e4b34da86a5 100644 --- a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts +++ b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.test.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { parse as parseUrl } from 'url'; import { OnPostAuthHandler, OnPostAuthToolkit, @@ -45,7 +46,7 @@ describe('DashboardOnlyModeRequestInterceptor', () => { test('should not redirects for not app/* requests', async () => { const request = ({ url: { - path: 'api/test', + pathname: 'api/test', }, } as unknown) as KibanaRequest; @@ -57,7 +58,7 @@ describe('DashboardOnlyModeRequestInterceptor', () => { test('should not redirects not authenticated users', async () => { const request = ({ url: { - path: '/app/home', + pathname: '/app/home', }, } as unknown) as KibanaRequest; @@ -70,10 +71,9 @@ describe('DashboardOnlyModeRequestInterceptor', () => { function testRedirectToDashboardModeApp(url: string) { describe(`requests to url:"${url}"`, () => { test('redirects to the dashboard_mode app instead', async () => { + const { pathname, search, hash } = parseUrl(url); const request = ({ - url: { - path: url, - }, + url: { pathname, search, hash }, credentials: { roles: [DASHBOARD_ONLY_MODE_ROLE], }, diff --git a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts index 4378c818f087c5..9978d18142ff58 100644 --- a/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts +++ b/x-pack/plugins/dashboard_mode/server/interceptors/dashboard_mode_request_interceptor.ts @@ -22,7 +22,7 @@ export const setupDashboardModeRequestInterceptor = ({ getUiSettingsClient, }: DashboardModeRequestInterceptorDependencies) => (async (request, response, toolkit) => { - const path = request.url.path || ''; + const path = request.url.pathname; const isAppRequest = path.startsWith('/app/'); if (!isAppRequest) { diff --git a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts index 2bddc9f1c80bd7..5bd15ce411002b 100644 --- a/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts +++ b/x-pack/plugins/enterprise_search/server/lib/enterprise_search_config_api.test.ts @@ -21,7 +21,6 @@ describe('callEnterpriseSearchConfigAPI', () => { accessCheckTimeoutWarning: 100, }; const mockRequest = { - url: { path: '/app/kibana' }, headers: { authorization: '==someAuth' }, }; const mockDependencies = { diff --git a/x-pack/plugins/event_log/server/event_log_client.test.ts b/x-pack/plugins/event_log/server/event_log_client.test.ts index d6793be4255857..d9846428b94888 100644 --- a/x-pack/plugins/event_log/server/event_log_client.test.ts +++ b/x-pack/plugins/event_log/server/event_log_client.test.ts @@ -322,6 +322,12 @@ function FakeRequest(): KibanaRequest { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, getSavedObjectsClient: () => savedObjectGetter, } as unknown) as KibanaRequest; } diff --git a/x-pack/plugins/event_log/server/event_log_start_service.test.ts b/x-pack/plugins/event_log/server/event_log_start_service.test.ts index 0a5b169e87d4d3..db6f4a1ad0f279 100644 --- a/x-pack/plugins/event_log/server/event_log_start_service.test.ts +++ b/x-pack/plugins/event_log/server/event_log_start_service.test.ts @@ -56,6 +56,12 @@ function fakeRequest(): KibanaRequest { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, getSavedObjectsClient: () => savedObjectsClient, } as unknown) as KibanaRequest; } diff --git a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts index 6a02d54c875145..076260ab2fe530 100644 --- a/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts +++ b/x-pack/plugins/event_log/server/saved_object_provider_registry.test.ts @@ -93,6 +93,12 @@ function fakeRequest(): KibanaRequest { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, getSavedObjectsClient: () => savedObjectsClient, } as unknown) as KibanaRequest; } diff --git a/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts b/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts index fe06de765bbff6..1ad710ba70e290 100644 --- a/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts +++ b/x-pack/plugins/ingest_manager/server/services/agent_policy_update.ts @@ -23,6 +23,12 @@ const fakeRequest = ({ url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, } as unknown) as KibanaRequest; export async function agentPolicyUpdateEventHandler( diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts index 994ecc64c82a75..b9ef36ecaae54e 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_connected_agents.ts @@ -23,6 +23,12 @@ function getInternalUserSOClient() { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, } as unknown) as KibanaRequest; return appContextService.getInternalUserSOClient(fakeRequest); diff --git a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts index aa48d8fe18e9ff..c0e8540004930f 100644 --- a/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts +++ b/x-pack/plugins/ingest_manager/server/services/agents/checkin/state_new_actions.ts @@ -58,6 +58,12 @@ function getInternalUserSOClient() { url: '/', }, }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, } as unknown) as KibanaRequest; return appContextService.getInternalUserSOClient(fakeRequest); diff --git a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts index e0f1b01dafa135..48aed19ea90505 100644 --- a/x-pack/plugins/ml/server/routes/data_frame_analytics.ts +++ b/x-pack/plugins/ml/server/routes/data_frame_analytics.ts @@ -456,16 +456,10 @@ export function dataFrameAnalyticsRoutes({ router, mlLicense }: RouteInitializat }, mlLicense.fullLicenseAPIGuard(async ({ client, request, response }) => { try { - const options: { id: string; force?: boolean | undefined } = { + const { body } = await client.asInternalUser.ml.stopDataFrameAnalytics({ id: request.params.analyticsId, - }; - // @ts-expect-error TODO: update types - if (request.url?.query?.force !== undefined) { - // @ts-expect-error TODO: update types - options.force = request.url.query.force; - } - - const { body } = await client.asInternalUser.ml.stopDataFrameAnalytics(options); + force: request.query.force, + }); return response.ok({ body, }); diff --git a/x-pack/plugins/reporting/server/core.ts b/x-pack/plugins/reporting/server/core.ts index abd86d51fb6b6d..d62adc62bc9aaf 100644 --- a/x-pack/plugins/reporting/server/core.ts +++ b/x-pack/plugins/reporting/server/core.ts @@ -210,11 +210,18 @@ export class ReportingCore { } public getFakeRequest(baseRequest: object, spaceId: string | undefined, logger = this.logger) { + // @ts-expect-error _core isn't supposed to be accessed - remove once we upgrade to hapi v18 const fakeRequest = KibanaRequest.from({ path: '/', route: { settings: {} }, url: { href: '/' }, raw: { req: { url: '/' } }, + // TODO: Remove once we upgrade to hapi v18 + _core: { + info: { + uri: 'http://localhost', + }, + }, ...baseRequest, } as Hapi.Request); diff --git a/x-pack/plugins/reporting/server/routes/legacy.ts b/x-pack/plugins/reporting/server/routes/legacy.ts index 4c08619f8b888a..50c90cefa189fd 100644 --- a/x-pack/plugins/reporting/server/routes/legacy.ts +++ b/x-pack/plugins/reporting/server/routes/legacy.ts @@ -38,7 +38,7 @@ export function registerLegacy( }, userHandler(async (user, context, req, res) => { - const message = `The following URL is deprecated and will stop working in the next major version: ${req.url.path}`; + const message = `The following URL is deprecated and will stop working in the next major version: ${req.url.pathname}${req.url.search}`; logger.warn(message, ['deprecation']); try { diff --git a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts index cee8a88000e298..cce002a0e69354 100644 --- a/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts +++ b/x-pack/plugins/reporting/server/routes/lib/authorized_user_pre_routing.test.ts @@ -27,7 +27,7 @@ const getMockContext = () => const getMockRequest = () => ({ - url: { port: '5601', query: '', path: '/foo' }, + url: { port: '5601', search: '', pathname: '/foo' }, route: { path: '/foo', options: {} }, } as KibanaRequest); diff --git a/x-pack/plugins/security/server/audit/audit_events.test.ts b/x-pack/plugins/security/server/audit/audit_events.test.ts index 1978795f82a247..f153b9efb9d435 100644 --- a/x-pack/plugins/security/server/audit/audit_events.test.ts +++ b/x-pack/plugins/security/server/audit/audit_events.test.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { URL } from 'url'; import { EventOutcome, SavedObjectAction, @@ -192,11 +193,11 @@ describe('#httpRequestEvent', () => { }, "message": "User is requesting [/path] endpoint", "url": Object { - "domain": undefined, + "domain": "localhost", "path": "/path", "port": undefined, "query": undefined, - "scheme": undefined, + "scheme": "http:", }, } `); @@ -211,12 +212,7 @@ describe('#httpRequestEvent', () => { kibanaRequestState: { requestId: '123', requestUuid: '123e4567-e89b-12d3-a456-426614174000', - rewrittenUrl: { - path: '/original/path', - pathname: '/original/path', - query: 'query=param', - search: '?query=param', - }, + rewrittenUrl: new URL('http://localhost/original/path?query=param'), }, }), }) @@ -234,11 +230,11 @@ describe('#httpRequestEvent', () => { }, "message": "User is requesting [/original/path] endpoint", "url": Object { - "domain": undefined, + "domain": "localhost", "path": "/original/path", "port": undefined, "query": "query=param", - "scheme": undefined, + "scheme": "http:", }, } `); diff --git a/x-pack/plugins/security/server/audit/audit_events.ts b/x-pack/plugins/security/server/audit/audit_events.ts index 1ff9da3a95ff4c..d91c18bf82e022 100644 --- a/x-pack/plugins/security/server/audit/audit_events.ts +++ b/x-pack/plugins/security/server/audit/audit_events.ts @@ -105,10 +105,10 @@ export interface HttpRequestParams { } export function httpRequestEvent({ request }: HttpRequestParams): AuditEvent { - const { pathname, search } = request.rewrittenUrl ?? request.url; + const url = request.rewrittenUrl ?? request.url; return { - message: `User is requesting [${pathname}] endpoint`, + message: `User is requesting [${url.pathname}] endpoint`, event: { action: 'http_request', category: EventCategory.WEB, @@ -120,11 +120,11 @@ export function httpRequestEvent({ request }: HttpRequestParams): AuditEvent { }, }, url: { - domain: request.url.hostname, - path: pathname, - port: request.url.port ? parseInt(request.url.port, 10) : undefined, - query: search?.slice(1) || undefined, - scheme: request.url.protocol, + domain: url.hostname, + path: url.pathname, + port: url.port ? parseInt(url.port, 10) : undefined, + query: url.search ? url.search.slice(1) : undefined, + scheme: url.protocol, }, }; } diff --git a/x-pack/plugins/security/server/authentication/authenticator.ts b/x-pack/plugins/security/server/authentication/authenticator.ts index aa3346c9f12378..f4cdea7c988d74 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.ts @@ -335,7 +335,7 @@ export class Authenticator { this.logger.debug('Redirecting request to Login Selector.'); return AuthenticationResult.redirectTo( `${this.options.basePath.serverBasePath}/login?next=${encodeURIComponent( - `${this.options.basePath.get(request)}${request.url.path}` + `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}` )}` ); } @@ -730,7 +730,7 @@ export class Authenticator { preAccessRedirectURL = `${preAccessRedirectURL}?next=${encodeURIComponent( authenticationResult.redirectURL || redirectURL || - `${this.options.basePath.get(request)}${request.url.path}` + `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}` )}`; } else if (redirectURL && !authenticationResult.redirectURL) { preAccessRedirectURL = redirectURL; diff --git a/x-pack/plugins/security/server/authentication/providers/basic.test.ts b/x-pack/plugins/security/server/authentication/providers/basic.test.ts index 2481844abb3896..87002ebed56725 100644 --- a/x-pack/plugins/security/server/authentication/providers/basic.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/basic.test.ts @@ -101,13 +101,13 @@ describe('BasicAuthenticationProvider', () => { await expect( provider.authenticate( httpServerMock.createKibanaRequest({ - path: '/s/foo/some-path # that needs to be encoded', + path: '/s/foo/some path that needs to be encoded', }), null ) ).resolves.toEqual( AuthenticationResult.redirectTo( - '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome-path%20%23%20that%20needs%20to%20be%20encoded' + '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome%2520path%2520that%2520needs%2520to%2520be%2520encoded' ) ); }); diff --git a/x-pack/plugins/security/server/authentication/providers/basic.ts b/x-pack/plugins/security/server/authentication/providers/basic.ts index 35ab2d242659a8..28b671346ee7f6 100644 --- a/x-pack/plugins/security/server/authentication/providers/basic.ts +++ b/x-pack/plugins/security/server/authentication/providers/basic.ts @@ -90,7 +90,9 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); if (HTTPAuthorizationHeader.parseFromRequest(request) != null) { this.logger.debug('Cannot authenticate requests with `Authorization` header.'); @@ -106,7 +108,9 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider { this.logger.debug('Redirecting request to Login page.'); const basePath = this.options.basePath.get(request); return AuthenticationResult.redirectTo( - `${basePath}/login?next=${encodeURIComponent(`${basePath}${request.url.path}`)}` + `${basePath}/login?next=${encodeURIComponent( + `${basePath}${request.url.pathname}${request.url.search}` + )}` ); } @@ -119,7 +123,7 @@ export class BasicAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Having a `null` state means that provider was specifically called to do a logout, but when // session isn't defined then provider is just being probed whether or not it can perform logout. diff --git a/x-pack/plugins/security/server/authentication/providers/http.ts b/x-pack/plugins/security/server/authentication/providers/http.ts index 3e33a52cbbc6b1..933685d68978f5 100644 --- a/x-pack/plugins/security/server/authentication/providers/http.ts +++ b/x-pack/plugins/security/server/authentication/providers/http.ts @@ -56,7 +56,9 @@ export class HTTPAuthenticationProvider extends BaseAuthenticationProvider { * @param request Request instance. */ public async authenticate(request: KibanaRequest) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request); if (authorizationHeader == null) { @@ -72,12 +74,12 @@ export class HTTPAuthenticationProvider extends BaseAuthenticationProvider { try { const user = await this.getUser(request); this.logger.debug( - `Request to ${request.url.path} has been authenticated via authorization header with "${authorizationHeader.scheme}" scheme.` + `Request to ${request.url.pathname}${request.url.search} has been authenticated via authorization header with "${authorizationHeader.scheme}" scheme.` ); return AuthenticationResult.succeeded(user); } catch (err) { this.logger.debug( - `Failed to authenticate request to ${request.url.path} via authorization header with "${authorizationHeader.scheme}" scheme: ${err.message}` + `Failed to authenticate request to ${request.url.pathname}${request.url.search} via authorization header with "${authorizationHeader.scheme}" scheme: ${err.message}` ); return AuthenticationResult.failed(err); } diff --git a/x-pack/plugins/security/server/authentication/providers/kerberos.ts b/x-pack/plugins/security/server/authentication/providers/kerberos.ts index 5b593851cc2f29..d7de71f4da9eda 100644 --- a/x-pack/plugins/security/server/authentication/providers/kerberos.ts +++ b/x-pack/plugins/security/server/authentication/providers/kerberos.ts @@ -65,7 +65,9 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); const authorizationHeader = HTTPAuthorizationHeader.parseFromRequest(request); if (authorizationHeader && authorizationHeader.scheme.toLowerCase() !== 'negotiate') { @@ -100,7 +102,7 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider { * @param state State value previously stored by the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Having a `null` state means that provider was specifically called to do a logout, but when // session isn't defined then provider is just being probed whether or not it can perform logout. diff --git a/x-pack/plugins/security/server/authentication/providers/oidc.ts b/x-pack/plugins/security/server/authentication/providers/oidc.ts index 75c909cdcd94b9..9570c59f8ea1d3 100644 --- a/x-pack/plugins/security/server/authentication/providers/oidc.ts +++ b/x-pack/plugins/security/server/authentication/providers/oidc.ts @@ -166,7 +166,9 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); if (HTTPAuthorizationHeader.parseFromRequest(request) != null) { this.logger.debug('Cannot authenticate requests with `Authorization` header.'); @@ -418,7 +420,7 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider { * @param state State value previously stored by the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Having a `null` state means that provider was specifically called to do a logout, but when // session isn't defined then provider is just being probed whether or not it can perform logout. @@ -477,7 +479,7 @@ export class OIDCAuthenticationProvider extends BaseAuthenticationProvider { `${ this.options.basePath.serverBasePath }/internal/security/capture-url?next=${encodeURIComponent( - `${this.options.basePath.get(request)}${request.url.path}` + `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}` )}&providerType=${encodeURIComponent(this.type)}&providerName=${encodeURIComponent( this.options.name )}`, diff --git a/x-pack/plugins/security/server/authentication/providers/pki.ts b/x-pack/plugins/security/server/authentication/providers/pki.ts index f3cc21500df26f..6dcb448e08150f 100644 --- a/x-pack/plugins/security/server/authentication/providers/pki.ts +++ b/x-pack/plugins/security/server/authentication/providers/pki.ts @@ -61,7 +61,9 @@ export class PKIAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); if (HTTPAuthorizationHeader.parseFromRequest(request) != null) { this.logger.debug('Cannot authenticate requests with `Authorization` header.'); @@ -105,7 +107,7 @@ export class PKIAuthenticationProvider extends BaseAuthenticationProvider { * @param state State value previously stored by the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Having a `null` state means that provider was specifically called to do a logout, but when // session isn't defined then provider is just being probed whether or not it can perform logout. diff --git a/x-pack/plugins/security/server/authentication/providers/saml.ts b/x-pack/plugins/security/server/authentication/providers/saml.ts index c8edf35cc8ec4d..d1b624be5977d8 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.ts @@ -191,7 +191,9 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}` + ); if (HTTPAuthorizationHeader.parseFromRequest(request) != null) { this.logger.debug('Cannot authenticate requests with `Authorization` header.'); @@ -230,7 +232,7 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider { * @param state State value previously stored by the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Normally when there is no active session in Kibana, `logout` method shouldn't do anything // and user will eventually be redirected to the home page to log in. But when SAML SLO is @@ -654,7 +656,7 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider { `${ this.options.basePath.serverBasePath }/internal/security/capture-url?next=${encodeURIComponent( - `${this.options.basePath.get(request)}${request.url.path}` + `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}` )}&providerType=${encodeURIComponent(this.type)}&providerName=${encodeURIComponent( this.options.name )}`, diff --git a/x-pack/plugins/security/server/authentication/providers/token.test.ts b/x-pack/plugins/security/server/authentication/providers/token.test.ts index 0264edf4fc082f..ffb1c89b24e478 100644 --- a/x-pack/plugins/security/server/authentication/providers/token.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/token.test.ts @@ -173,13 +173,13 @@ describe('TokenAuthenticationProvider', () => { await expect( provider.authenticate( httpServerMock.createKibanaRequest({ - path: '/s/foo/some-path # that needs to be encoded', + path: '/s/foo/some path that needs to be encoded', }), null ) ).resolves.toEqual( AuthenticationResult.redirectTo( - '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome-path%20%23%20that%20needs%20to%20be%20encoded' + '/mock-server-basepath/login?next=%2Fmock-server-basepath%2Fs%2Ffoo%2Fsome%2520path%2520that%2520needs%2520to%2520be%2520encoded' ) ); }); diff --git a/x-pack/plugins/security/server/authentication/providers/token.ts b/x-pack/plugins/security/server/authentication/providers/token.ts index 869fd69173e2ed..7dace488bc95a6 100644 --- a/x-pack/plugins/security/server/authentication/providers/token.ts +++ b/x-pack/plugins/security/server/authentication/providers/token.ts @@ -92,7 +92,9 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider { * @param [state] Optional state object associated with the provider. */ public async authenticate(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to authenticate user request to ${request.url.path}.`); + this.logger.debug( + `Trying to authenticate user request to ${request.url.pathname}${request.url.search}.` + ); if (HTTPAuthorizationHeader.parseFromRequest(request) != null) { this.logger.debug('Cannot authenticate requests with `Authorization` header.'); @@ -126,7 +128,7 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider { * @param state State value previously stored by the provider. */ public async logout(request: KibanaRequest, state?: ProviderState | null) { - this.logger.debug(`Trying to log user out via ${request.url.path}.`); + this.logger.debug(`Trying to log user out via ${request.url.pathname}${request.url.search}.`); // Having a `null` state means that provider was specifically called to do a logout, but when // session isn't defined then provider is just being probed whether or not it can perform logout. @@ -241,7 +243,9 @@ export class TokenAuthenticationProvider extends BaseAuthenticationProvider { * @param request Request instance. */ private getLoginPageURL(request: KibanaRequest) { - const nextURL = encodeURIComponent(`${this.options.basePath.get(request)}${request.url.path}`); + const nextURL = encodeURIComponent( + `${this.options.basePath.get(request)}${request.url.pathname}${request.url.search}` + ); return `${this.options.basePath.get(request)}/login?next=${nextURL}`; } } diff --git a/x-pack/plugins/security/server/authorization/api_authorization.ts b/x-pack/plugins/security/server/authorization/api_authorization.ts index 813ed8d064d94c..9cf090ab271aea 100644 --- a/x-pack/plugins/security/server/authorization/api_authorization.ts +++ b/x-pack/plugins/security/server/authorization/api_authorization.ts @@ -33,11 +33,13 @@ export function initAPIAuthorization( // we've actually authorized the request if (checkPrivilegesResponse.hasAllRequested) { - logger.debug(`User authorized for "${request.url.path}"`); + logger.debug(`User authorized for "${request.url.pathname}${request.url.search}"`); return toolkit.next(); } - logger.warn(`User not authorized for "${request.url.path}": responding with 403`); + logger.warn( + `User not authorized for "${request.url.pathname}${request.url.search}": responding with 403` + ); return response.forbidden(); }); } diff --git a/x-pack/plugins/security/server/authorization/authorization_service.tsx b/x-pack/plugins/security/server/authorization/authorization_service.tsx index 9547295af4dfb7..a45bca90d8b56f 100644 --- a/x-pack/plugins/security/server/authorization/authorization_service.tsx +++ b/x-pack/plugins/security/server/authorization/authorization_service.tsx @@ -168,7 +168,7 @@ export class AuthorizationService { http.registerOnPreResponse((request, preResponse, toolkit) => { if (preResponse.statusCode === 403 && canRedirectRequest(request)) { const basePath = http.basePath.get(request); - const next = `${basePath}${request.url.path}`; + const next = `${basePath}${request.url.pathname}${request.url.search}`; const regularBundlePath = `${basePath}/${buildNumber}/bundles`; const logoutUrl = http.basePath.prepend( diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts index 5d8a7ae7bdfea8..7eaa619b330e06 100644 --- a/x-pack/plugins/security/server/routes/authentication/oidc.ts +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -135,7 +135,7 @@ export function defineOIDCRoutes({ loginAttempt = { type: OIDCLogin.LoginWithAuthorizationCodeFlow, // We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway. - authenticationResponseURI: request.url.path!, + authenticationResponseURI: request.url.pathname + request.url.search, }; } else if (request.query.iss) { logger.warn( diff --git a/x-pack/plugins/security/server/routes/views/login.test.ts b/x-pack/plugins/security/server/routes/views/login.test.ts index fee3adbb19f978..b90a44be7aade1 100644 --- a/x-pack/plugins/security/server/routes/views/login.test.ts +++ b/x-pack/plugins/security/server/routes/views/login.test.ts @@ -100,7 +100,7 @@ describe('Login view routes', () => { auth: { isAuthenticated: true }, }); (request as any).url = new URL( - `${request.url.path}${request.url.search}`, + `${request.url.pathname}${request.url.search}`, 'https://kibana.co' ); license.getFeatures.mockReturnValue({ showLogin: true } as any); @@ -114,7 +114,7 @@ describe('Login view routes', () => { // Redirect if `showLogin` is `false` even if user is not authenticated. request = httpServerMock.createKibanaRequest({ query, auth: { isAuthenticated: false } }); (request as any).url = new URL( - `${request.url.path}${request.url.search}`, + `${request.url.pathname}${request.url.search}`, 'https://kibana.co' ); license.getFeatures.mockReturnValue({ showLogin: false } as any); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts index e3a724e153688b..1aa2011a15b35d 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_post_auth_interceptor.ts @@ -28,7 +28,7 @@ export function initSpacesOnPostAuthRequestInterceptor({ http.registerOnPostAuth(async (request, response, toolkit) => { const serverBasePath = http.basePath.serverBasePath; - const path = request.url.pathname!; + const path = request.url.pathname; const spaceId = spacesService.getSpaceId(request); diff --git a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts index 6408803c2114bc..a3335b1e075f20 100644 --- a/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts +++ b/x-pack/plugins/spaces/server/lib/request_interceptors/on_request_interceptor.ts @@ -9,8 +9,6 @@ import { LifecycleResponseFactory, CoreSetup, } from 'src/core/server'; -import { format } from 'url'; -import { modifyUrl } from '../utils/url'; import { getSpaceIdFromPath } from '../../../common'; export interface OnRequestInterceptorDeps { @@ -34,16 +32,9 @@ export function initSpacesOnRequestInterceptor({ http }: OnRequestInterceptorDep http.basePath.set(request, reqBasePath); - const newLocation = (path && path.substr(reqBasePath.length)) || '/'; + const newPathname = path.substr(reqBasePath.length) || '/'; - const newUrl = modifyUrl(format(request.url), (parts) => { - return { - ...parts, - pathname: newLocation, - }; - }); - - return toolkit.rewriteUrl(newUrl); + return toolkit.rewriteUrl(`${newPathname}${request.url.search}`); } return toolkit.next(); diff --git a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts index b48bf971d0c1be..d1e1d81134940e 100644 --- a/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts +++ b/x-pack/plugins/spaces/server/spaces_service/spaces_service.test.ts @@ -58,7 +58,7 @@ const createService = async (serverBasePath: string = '') => { serverBasePath, } as HttpServiceSetup['basePath']; httpSetup.basePath.get = jest.fn().mockImplementation((request: KibanaRequest) => { - const { spaceId } = getSpaceIdFromPath(request.url.path); + const { spaceId } = getSpaceIdFromPath(request.url.pathname); if (spaceId !== DEFAULT_SPACE_ID) { return `/s/${spaceId}`; @@ -83,7 +83,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - url: { path: '/app/kibana' }, + url: { pathname: '/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.getSpaceId(request)).toEqual(DEFAULT_SPACE_ID); @@ -93,7 +93,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - url: { path: '/s/foo/app/kibana' }, + url: { pathname: '/s/foo/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.getSpaceId(request)).toEqual('foo'); @@ -140,7 +140,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - url: { path: '/app/kibana' }, + url: { pathname: '/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(true); @@ -150,7 +150,7 @@ describe('SpacesService', () => { const spacesServiceSetup = await createService(); const request: KibanaRequest = { - url: { path: '/s/foo/app/kibana' }, + url: { pathname: '/s/foo/app/kibana' }, } as KibanaRequest; expect(spacesServiceSetup.isInDefaultSpace(request)).toEqual(false);