diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md index b12983836d9e5a..474dc6b7d6f282 100644 --- a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.md @@ -88,8 +88,9 @@ async (context, request, response) => { | [csp](./kibana-plugin-core-server.httpservicesetup.csp.md) | ICspConfig | The CSP config used for Kibana. | | [getServerInfo](./kibana-plugin-core-server.httpservicesetup.getserverinfo.md) | () => HttpServerInfo | Provides common [information](./kibana-plugin-core-server.httpserverinfo.md) about the running http server. | | [registerAuth](./kibana-plugin-core-server.httpservicesetup.registerauth.md) | (handler: AuthenticationHandler) => void | To define custom authentication and/or authorization mechanism for incoming requests. | -| [registerOnPostAuth](./kibana-plugin-core-server.httpservicesetup.registeronpostauth.md) | (handler: OnPostAuthHandler) => void | To define custom logic to perform for incoming requests. | -| [registerOnPreAuth](./kibana-plugin-core-server.httpservicesetup.registeronpreauth.md) | (handler: OnPreAuthHandler) => void | To define custom logic to perform for incoming requests. | +| [registerOnPostAuth](./kibana-plugin-core-server.httpservicesetup.registeronpostauth.md) | (handler: OnPostAuthHandler) => void | To define custom logic after Auth interceptor did make sure a user has access to the requested resource. | +| [registerOnPreAuth](./kibana-plugin-core-server.httpservicesetup.registeronpreauth.md) | (handler: OnPreAuthHandler) => void | To define custom logic to perform for incoming requests before the Auth interceptor performs a check that user has access to requested resources. | | [registerOnPreResponse](./kibana-plugin-core-server.httpservicesetup.registeronpreresponse.md) | (handler: OnPreResponseHandler) => void | To define custom logic to perform for the server response. | +| [registerOnPreRouting](./kibana-plugin-core-server.httpservicesetup.registeronprerouting.md) | (handler: OnPreRoutingHandler) => void | To define custom logic to perform for incoming requests before server performs a route lookup. | | [registerRouteHandlerContext](./kibana-plugin-core-server.httpservicesetup.registerroutehandlercontext.md) | <T extends keyof RequestHandlerContext>(contextName: T, provider: RequestHandlerContextProvider<T>) => RequestHandlerContextContainer | Register a context provider for a route handler. | diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpostauth.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpostauth.md index 01294693e282fc..eff53b7b75fa59 100644 --- a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpostauth.md +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpostauth.md @@ -4,7 +4,7 @@ ## HttpServiceSetup.registerOnPostAuth property -To define custom logic to perform for incoming requests. +To define custom logic after Auth interceptor did make sure a user has access to the requested resource. Signature: @@ -14,5 +14,5 @@ registerOnPostAuth: (handler: OnPostAuthHandler) => void; ## Remarks -Runs the handler after Auth interceptor did make sure a user has access to the requested resource. The auth state is available at stage via http.auth.get(..) Can register any number of registerOnPreAuth, which are called in sequence (from the first registered to the last). See [OnPostAuthHandler](./kibana-plugin-core-server.onpostauthhandler.md). +The auth state is available at stage via http.auth.get(..) Can register any number of registerOnPreRouting, which are called in sequence (from the first registered to the last). See [OnPostAuthHandler](./kibana-plugin-core-server.onpostauthhandler.md). diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpreauth.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpreauth.md index f11453c8cda987..ce4cacb1c87490 100644 --- a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpreauth.md +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronpreauth.md @@ -4,7 +4,7 @@ ## HttpServiceSetup.registerOnPreAuth property -To define custom logic to perform for incoming requests. +To define custom logic to perform for incoming requests before the Auth interceptor performs a check that user has access to requested resources. Signature: @@ -14,5 +14,5 @@ registerOnPreAuth: (handler: OnPreAuthHandler) => void; ## Remarks -Runs the handler before Auth interceptor performs a check that user has access to requested resources, so it's the only place when you can forward a request to another URL right on the server. Can register any number of registerOnPostAuth, which are called in sequence (from the first registered to the last). See [OnPreAuthHandler](./kibana-plugin-core-server.onpreauthhandler.md). +Can register any number of registerOnPostAuth, which are called in sequence (from the first registered to the last). See [OnPreRoutingHandler](./kibana-plugin-core-server.onpreroutinghandler.md). diff --git a/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronprerouting.md b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronprerouting.md new file mode 100644 index 00000000000000..bdf5f158286695 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.httpservicesetup.registeronprerouting.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [HttpServiceSetup](./kibana-plugin-core-server.httpservicesetup.md) > [registerOnPreRouting](./kibana-plugin-core-server.httpservicesetup.registeronprerouting.md) + +## HttpServiceSetup.registerOnPreRouting property + +To define custom logic to perform for incoming requests before server performs a route lookup. + +Signature: + +```typescript +registerOnPreRouting: (handler: OnPreRoutingHandler) => void; +``` + +## Remarks + +It's the only place when you can forward a request to another URL right on the server. Can register any number of registerOnPreRouting, which are called in sequence (from the first registered to the last). See [OnPreRoutingHandler](./kibana-plugin-core-server.onpreroutinghandler.md). + diff --git a/docs/development/core/server/kibana-plugin-core-server.md b/docs/development/core/server/kibana-plugin-core-server.md index 8d4c0c915437eb..a665327454c1a6 100644 --- a/docs/development/core/server/kibana-plugin-core-server.md +++ b/docs/development/core/server/kibana-plugin-core-server.md @@ -122,7 +122,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. | | [OnPreResponseExtensions](./kibana-plugin-core-server.onpreresponseextensions.md) | Additional data to extend a response. | | [OnPreResponseInfo](./kibana-plugin-core-server.onpreresponseinfo.md) | Response status code. | -| [OnPreResponseToolkit](./kibana-plugin-core-server.onpreresponsetoolkit.md) | A tool set defining an outcome of OnPreAuth interceptor for incoming request. | +| [OnPreResponseToolkit](./kibana-plugin-core-server.onpreresponsetoolkit.md) | A tool set defining an outcome of OnPreRouting interceptor for incoming request. | +| [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md) | A tool set defining an outcome of OnPreRouting interceptor for incoming request. | | [OpsMetrics](./kibana-plugin-core-server.opsmetrics.md) | Regroups metrics gathered by all the collectors. This contains metrics about the os/runtime, the kibana process and the http server. | | [OpsOsMetrics](./kibana-plugin-core-server.opsosmetrics.md) | OS related metrics | | [OpsProcessMetrics](./kibana-plugin-core-server.opsprocessmetrics.md) | Process related metrics | @@ -256,7 +257,8 @@ The plugin integrates with the core system via lifecycle events: `setup` | [MutatingOperationRefreshSetting](./kibana-plugin-core-server.mutatingoperationrefreshsetting.md) | Elasticsearch Refresh setting for mutating operation | | [OnPostAuthHandler](./kibana-plugin-core-server.onpostauthhandler.md) | See [OnPostAuthToolkit](./kibana-plugin-core-server.onpostauthtoolkit.md). | | [OnPreAuthHandler](./kibana-plugin-core-server.onpreauthhandler.md) | See [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md). | -| [OnPreResponseHandler](./kibana-plugin-core-server.onpreresponsehandler.md) | See [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md). | +| [OnPreResponseHandler](./kibana-plugin-core-server.onpreresponsehandler.md) | See [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md). | +| [OnPreRoutingHandler](./kibana-plugin-core-server.onpreroutinghandler.md) | See [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md). | | [PluginConfigSchema](./kibana-plugin-core-server.pluginconfigschema.md) | Dedicated type for plugin configuration schema. | | [PluginInitializer](./kibana-plugin-core-server.plugininitializer.md) | The plugin export at the root of a plugin's server directory should conform to this interface. | | [PluginName](./kibana-plugin-core-server.pluginname.md) | Dedicated type for plugin name/id that is supposed to make Map/Set/Arrays that use it as a key or value more obvious. | diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.md b/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.md index 4097cb32c397af..8031dbc64fa6db 100644 --- a/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.md +++ b/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.md @@ -17,5 +17,4 @@ export interface OnPreAuthToolkit | Property | Type | Description | | --- | --- | --- | | [next](./kibana-plugin-core-server.onpreauthtoolkit.next.md) | () => OnPreAuthResult | To pass request to the next handler | -| [rewriteUrl](./kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md) | (url: string) => OnPreAuthResult | Rewrite requested resources url before is was authenticated and routed to a handler | diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md b/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md deleted file mode 100644 index 7ecde62f883027..00000000000000 --- a/docs/development/core/server/kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md) > [rewriteUrl](./kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md) - -## OnPreAuthToolkit.rewriteUrl property - -Rewrite requested resources url before is was authenticated and routed to a handler - -Signature: - -```typescript -rewriteUrl: (url: string) => OnPreAuthResult; -``` diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreresponsehandler.md b/docs/development/core/server/kibana-plugin-core-server.onpreresponsehandler.md index e7eab8ee34d6fd..10696fb79a2f65 100644 --- a/docs/development/core/server/kibana-plugin-core-server.onpreresponsehandler.md +++ b/docs/development/core/server/kibana-plugin-core-server.onpreresponsehandler.md @@ -4,7 +4,7 @@ ## OnPreResponseHandler type -See [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md). +See [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md). Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreresponsetoolkit.md b/docs/development/core/server/kibana-plugin-core-server.onpreresponsetoolkit.md index 8e33e945b4ef9d..306c375ba4a3c3 100644 --- a/docs/development/core/server/kibana-plugin-core-server.onpreresponsetoolkit.md +++ b/docs/development/core/server/kibana-plugin-core-server.onpreresponsetoolkit.md @@ -4,7 +4,7 @@ ## OnPreResponseToolkit interface -A tool set defining an outcome of OnPreAuth interceptor for incoming request. +A tool set defining an outcome of OnPreRouting interceptor for incoming request. Signature: diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreroutinghandler.md b/docs/development/core/server/kibana-plugin-core-server.onpreroutinghandler.md new file mode 100644 index 00000000000000..46016bcd5476a0 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.onpreroutinghandler.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OnPreRoutingHandler](./kibana-plugin-core-server.onpreroutinghandler.md) + +## OnPreRoutingHandler type + +See [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md). + +Signature: + +```typescript +export declare type OnPreRoutingHandler = (request: KibanaRequest, response: LifecycleResponseFactory, toolkit: OnPreRoutingToolkit) => OnPreRoutingResult | KibanaResponse | Promise; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.md b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.md new file mode 100644 index 00000000000000..c564896b46a27e --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md) + +## OnPreRoutingToolkit interface + +A tool set defining an outcome of OnPreRouting interceptor for incoming request. + +Signature: + +```typescript +export interface OnPreRoutingToolkit +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [next](./kibana-plugin-core-server.onpreroutingtoolkit.next.md) | () => OnPreRoutingResult | To pass request to the next handler | +| [rewriteUrl](./kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md) | (url: string) => OnPreRoutingResult | Rewrite requested resources url before is was authenticated and routed to a handler | + diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.next.md b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.next.md new file mode 100644 index 00000000000000..7fb0b2ce67ba5d --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.next.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md) > [next](./kibana-plugin-core-server.onpreroutingtoolkit.next.md) + +## OnPreRoutingToolkit.next property + +To pass request to the next handler + +Signature: + +```typescript +next: () => OnPreRoutingResult; +``` diff --git a/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md new file mode 100644 index 00000000000000..346a12711c7238 --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md) > [rewriteUrl](./kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md) + +## OnPreRoutingToolkit.rewriteUrl property + +Rewrite requested resources url before is was authenticated and routed to a handler + +Signature: + +```typescript +rewriteUrl: (url: string) => OnPreRoutingResult; +``` diff --git a/src/core/server/http/http_server.mocks.ts b/src/core/server/http/http_server.mocks.ts index bbef0a105c0896..7d37af833d4c17 100644 --- a/src/core/server/http/http_server.mocks.ts +++ b/src/core/server/http/http_server.mocks.ts @@ -33,7 +33,7 @@ import { } from './router'; import { OnPreResponseToolkit } from './lifecycle/on_pre_response'; import { OnPostAuthToolkit } from './lifecycle/on_post_auth'; -import { OnPreAuthToolkit } from './lifecycle/on_pre_auth'; +import { OnPreRoutingToolkit } from './lifecycle/on_pre_routing'; interface RequestFixtureOptions

{ auth?: { isAuthenticated: boolean }; @@ -161,7 +161,7 @@ const createLifecycleResponseFactoryMock = (): jest.Mocked; +type ToolkitMock = jest.Mocked; const createToolkitMock = (): ToolkitMock => { return { diff --git a/src/core/server/http/http_server.test.ts b/src/core/server/http/http_server.test.ts index 72cb0b2821c5c2..601eba835a54e8 100644 --- a/src/core/server/http/http_server.test.ts +++ b/src/core/server/http/http_server.test.ts @@ -1089,6 +1089,16 @@ describe('setup contract', () => { }); }); + describe('#registerOnPreRouting', () => { + test('does not throw if called after stop', async () => { + const { registerOnPreRouting } = await server.setup(config); + await server.stop(); + expect(() => { + registerOnPreRouting((req, res) => res.unauthorized()); + }).not.toThrow(); + }); + }); + describe('#registerOnPreAuth', () => { test('does not throw if called after stop', async () => { const { registerOnPreAuth } = await server.setup(config); diff --git a/src/core/server/http/http_server.ts b/src/core/server/http/http_server.ts index 1abf5c0c133bbe..9c16162d693348 100644 --- a/src/core/server/http/http_server.ts +++ b/src/core/server/http/http_server.ts @@ -24,8 +24,9 @@ import { Logger, LoggerFactory } from '../logging'; import { HttpConfig } from './http_config'; import { createServer, getListenerOptions, getServerOptions } from './http_tools'; import { adoptToHapiAuthFormat, AuthenticationHandler } from './lifecycle/auth'; +import { adoptToHapiOnPreAuth, OnPreAuthHandler } from './lifecycle/on_pre_auth'; import { adoptToHapiOnPostAuthFormat, OnPostAuthHandler } from './lifecycle/on_post_auth'; -import { adoptToHapiOnPreAuthFormat, OnPreAuthHandler } from './lifecycle/on_pre_auth'; +import { adoptToHapiOnRequest, OnPreRoutingHandler } from './lifecycle/on_pre_routing'; import { adoptToHapiOnPreResponseFormat, OnPreResponseHandler } from './lifecycle/on_pre_response'; import { IRouter, RouteConfigOptions, KibanaRouteState, isSafeMethod } from './router'; import { @@ -49,8 +50,9 @@ export interface HttpServerSetup { basePath: HttpServiceSetup['basePath']; csp: HttpServiceSetup['csp']; createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory']; - registerAuth: HttpServiceSetup['registerAuth']; + registerOnPreRouting: HttpServiceSetup['registerOnPreRouting']; registerOnPreAuth: HttpServiceSetup['registerOnPreAuth']; + registerAuth: HttpServiceSetup['registerAuth']; registerOnPostAuth: HttpServiceSetup['registerOnPostAuth']; registerOnPreResponse: HttpServiceSetup['registerOnPreResponse']; getAuthHeaders: GetAuthHeaders; @@ -64,7 +66,11 @@ export interface HttpServerSetup { /** @internal */ export type LifecycleRegistrar = Pick< HttpServerSetup, - 'registerAuth' | 'registerOnPreAuth' | 'registerOnPostAuth' | 'registerOnPreResponse' + | 'registerOnPreRouting' + | 'registerOnPreAuth' + | 'registerAuth' + | 'registerOnPostAuth' + | 'registerOnPreResponse' >; export class HttpServer { @@ -113,12 +119,13 @@ export class HttpServer { return { registerRouter: this.registerRouter.bind(this), registerStaticDir: this.registerStaticDir.bind(this), + registerOnPreRouting: this.registerOnPreRouting.bind(this), registerOnPreAuth: this.registerOnPreAuth.bind(this), + registerAuth: this.registerAuth.bind(this), registerOnPostAuth: this.registerOnPostAuth.bind(this), registerOnPreResponse: this.registerOnPreResponse.bind(this), createCookieSessionStorageFactory: (cookieOptions: SessionStorageCookieOptions) => this.createCookieSessionStorageFactory(cookieOptions, config.basePath), - registerAuth: this.registerAuth.bind(this), basePath: basePathService, csp: config.csp, auth: { @@ -222,7 +229,7 @@ export class HttpServer { return; } - this.registerOnPreAuth((request, response, toolkit) => { + this.registerOnPreRouting((request, response, toolkit) => { const oldUrl = request.url.href!; const newURL = basePathService.remove(oldUrl); const shouldRedirect = newURL !== oldUrl; @@ -263,6 +270,17 @@ export class HttpServer { } } + private registerOnPreAuth(fn: OnPreAuthHandler) { + if (this.server === undefined) { + throw new Error('Server is not created yet'); + } + if (this.stopped) { + this.log.warn(`registerOnPreAuth called after stop`); + } + + this.server.ext('onPreAuth', adoptToHapiOnPreAuth(fn, this.log)); + } + private registerOnPostAuth(fn: OnPostAuthHandler) { if (this.server === undefined) { throw new Error('Server is not created yet'); @@ -274,15 +292,15 @@ export class HttpServer { this.server.ext('onPostAuth', adoptToHapiOnPostAuthFormat(fn, this.log)); } - private registerOnPreAuth(fn: OnPreAuthHandler) { + private registerOnPreRouting(fn: OnPreRoutingHandler) { if (this.server === undefined) { throw new Error('Server is not created yet'); } if (this.stopped) { - this.log.warn(`registerOnPreAuth called after stop`); + this.log.warn(`registerOnPreRouting called after stop`); } - this.server.ext('onRequest', adoptToHapiOnPreAuthFormat(fn, this.log)); + this.server.ext('onRequest', adoptToHapiOnRequest(fn, this.log)); } private registerOnPreResponse(fn: OnPreResponseHandler) { diff --git a/src/core/server/http/http_service.mock.ts b/src/core/server/http/http_service.mock.ts index 5e7ee7b658ecae..51f11b15f2e097 100644 --- a/src/core/server/http/http_service.mock.ts +++ b/src/core/server/http/http_service.mock.ts @@ -29,7 +29,7 @@ import { } from './types'; import { HttpService } from './http_service'; import { AuthStatus } from './auth_state_storage'; -import { OnPreAuthToolkit } from './lifecycle/on_pre_auth'; +import { OnPreRoutingToolkit } from './lifecycle/on_pre_routing'; import { AuthToolkit } from './lifecycle/auth'; import { sessionStorageMock } from './cookie_session_storage.mocks'; import { OnPostAuthToolkit } from './lifecycle/on_post_auth'; @@ -87,6 +87,7 @@ const createInternalSetupContractMock = () => { config: jest.fn().mockReturnValue(configMock.create()), } as unknown) as jest.MockedClass, createCookieSessionStorageFactory: jest.fn(), + registerOnPreRouting: jest.fn(), registerOnPreAuth: jest.fn(), registerAuth: jest.fn(), registerOnPostAuth: jest.fn(), @@ -117,7 +118,8 @@ const createSetupContractMock = () => { const mock: HttpServiceSetupMock = { createCookieSessionStorageFactory: internalMock.createCookieSessionStorageFactory, - registerOnPreAuth: internalMock.registerOnPreAuth, + registerOnPreRouting: internalMock.registerOnPreRouting, + registerOnPreAuth: jest.fn(), registerAuth: internalMock.registerAuth, registerOnPostAuth: internalMock.registerOnPostAuth, registerOnPreResponse: internalMock.registerOnPreResponse, @@ -173,7 +175,7 @@ const createHttpServiceMock = () => { return mocked; }; -const createOnPreAuthToolkitMock = (): jest.Mocked => ({ +const createOnPreAuthToolkitMock = (): jest.Mocked => ({ next: jest.fn(), rewriteUrl: jest.fn(), }); diff --git a/src/core/server/http/index.ts b/src/core/server/http/index.ts index 65d633260a7911..e91f7d93758429 100644 --- a/src/core/server/http/index.ts +++ b/src/core/server/http/index.ts @@ -64,7 +64,7 @@ export { SafeRouteMethod, } from './router'; export { BasePathProxyServer } from './base_path_proxy_server'; -export { OnPreAuthHandler, OnPreAuthToolkit } from './lifecycle/on_pre_auth'; +export { OnPreRoutingHandler, OnPreRoutingToolkit } from './lifecycle/on_pre_routing'; export { AuthenticationHandler, AuthHeaders, @@ -78,6 +78,7 @@ export { AuthResultType, } from './lifecycle/auth'; export { OnPostAuthHandler, OnPostAuthToolkit } from './lifecycle/on_post_auth'; +export { OnPreAuthHandler, OnPreAuthToolkit } from './lifecycle/on_pre_auth'; export { OnPreResponseHandler, OnPreResponseToolkit, diff --git a/src/core/server/http/integration_tests/core_services.test.ts b/src/core/server/http/integration_tests/core_services.test.ts index 0ee53a04d9f87d..3c5f22500e5e04 100644 --- a/src/core/server/http/integration_tests/core_services.test.ts +++ b/src/core/server/http/integration_tests/core_services.test.ts @@ -337,7 +337,7 @@ describe('http service', () => { it('basePath information for an incoming request is available in legacy server', async () => { const reqBasePath = '/requests-specific-base-path'; const { http } = await root.setup(); - http.registerOnPreAuth((req, res, toolkit) => { + http.registerOnPreRouting((req, res, toolkit) => { http.basePath.set(req, reqBasePath); return toolkit.next(); }); diff --git a/src/core/server/http/integration_tests/lifecycle.test.ts b/src/core/server/http/integration_tests/lifecycle.test.ts index cbab14115ba6b0..b9548bf7a8d707 100644 --- a/src/core/server/http/integration_tests/lifecycle.test.ts +++ b/src/core/server/http/integration_tests/lifecycle.test.ts @@ -57,20 +57,22 @@ interface StorageData { expires: number; } -describe('OnPreAuth', () => { +describe('OnPreRouting', () => { it('supports registering a request interceptor', async () => { - const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps); + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); const router = createRouter('/'); router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' })); const callingOrder: string[] = []; - registerOnPreAuth((req, res, t) => { + registerOnPreRouting((req, res, t) => { callingOrder.push('first'); return t.next(); }); - registerOnPreAuth((req, res, t) => { + registerOnPreRouting((req, res, t) => { callingOrder.push('second'); return t.next(); }); @@ -82,7 +84,9 @@ describe('OnPreAuth', () => { }); it('supports request forwarding to specified url', async () => { - const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps); + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); const router = createRouter('/'); router.get({ path: '/initial', validate: false }, (context, req, res) => @@ -93,13 +97,13 @@ describe('OnPreAuth', () => { ); let urlBeforeForwarding; - registerOnPreAuth((req, res, t) => { + registerOnPreRouting((req, res, t) => { urlBeforeForwarding = ensureRawRequest(req).raw.req.url; return t.rewriteUrl('/redirectUrl'); }); let urlAfterForwarding; - registerOnPreAuth((req, res, t) => { + registerOnPreRouting((req, res, t) => { // used by legacy platform urlAfterForwarding = ensureRawRequest(req).raw.req.url; return t.next(); @@ -113,6 +117,152 @@ describe('OnPreAuth', () => { expect(urlAfterForwarding).toBe('/redirectUrl'); }); + it('supports redirection from the interceptor', async () => { + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); + const router = createRouter('/'); + + const redirectUrl = '/redirectUrl'; + router.get({ path: '/initial', validate: false }, (context, req, res) => res.ok()); + + registerOnPreRouting((req, res, t) => + res.redirected({ + headers: { + location: redirectUrl, + }, + }) + ); + await server.start(); + + const result = await supertest(innerServer.listener).get('/initial').expect(302); + + expect(result.header.location).toBe(redirectUrl); + }); + + it('supports rejecting request and adjusting response headers', async () => { + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); + const router = createRouter('/'); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok()); + + registerOnPreRouting((req, res, t) => + res.unauthorized({ + headers: { + 'www-authenticate': 'challenge', + }, + }) + ); + await server.start(); + + const result = await supertest(innerServer.listener).get('/').expect(401); + + expect(result.header['www-authenticate']).toBe('challenge'); + }); + + it('does not expose error details if interceptor throws', async () => { + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); + const router = createRouter('/'); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok()); + + registerOnPreRouting((req, res, t) => { + throw new Error('reason'); + }); + await server.start(); + + const result = await supertest(innerServer.listener).get('/').expect(500); + + expect(result.body.message).toBe('An internal server error occurred.'); + expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ + Array [ + [Error: reason], + ], + ] + `); + }); + + it('returns internal error if interceptor returns unexpected result', async () => { + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); + const router = createRouter('/'); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok()); + + registerOnPreRouting((req, res, t) => ({} as any)); + await server.start(); + + const result = await supertest(innerServer.listener).get('/').expect(500); + + expect(result.body.message).toBe('An internal server error occurred.'); + expect(loggingSystemMock.collect(logger).error).toMatchInlineSnapshot(` + Array [ + Array [ + [Error: Unexpected result from OnPreRouting. Expected OnPreRoutingResult or KibanaResponse, but given: [object Object].], + ], + ] + `); + }); + + it(`doesn't share request object between interceptors`, async () => { + const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup( + setupDeps + ); + const router = createRouter('/'); + + registerOnPreRouting((req, res, t) => { + // don't complain customField is not defined on Request type + (req as any).customField = { value: 42 }; + return t.next(); + }); + registerOnPreRouting((req, res, t) => { + // don't complain customField is not defined on Request type + if (typeof (req as any).customField !== 'undefined') { + throw new Error('Request object was mutated'); + } + return t.next(); + }); + router.get({ path: '/', validate: false }, (context, req, res) => + // don't complain customField is not defined on Request type + res.ok({ body: { customField: String((req as any).customField) } }) + ); + + await server.start(); + + await supertest(innerServer.listener).get('/').expect(200, { customField: 'undefined' }); + }); +}); + +describe('OnPreAuth', () => { + it('supports registering a request interceptor', async () => { + const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps); + const router = createRouter('/'); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' })); + + const callingOrder: string[] = []; + registerOnPreAuth((req, res, t) => { + callingOrder.push('first'); + return t.next(); + }); + + registerOnPreAuth((req, res, t) => { + callingOrder.push('second'); + return t.next(); + }); + await server.start(); + + await supertest(innerServer.listener).get('/').expect(200, 'ok'); + + expect(callingOrder).toEqual(['first', 'second']); + }); + it('supports redirection from the interceptor', async () => { const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps); const router = createRouter('/'); @@ -203,20 +353,20 @@ describe('OnPreAuth', () => { const router = createRouter('/'); registerOnPreAuth((req, res, t) => { - // don't complain customField is not defined on Request type - (req as any).customField = { value: 42 }; + // @ts-expect-error customField property is not defined on request object + req.customField = { value: 42 }; return t.next(); }); registerOnPreAuth((req, res, t) => { - // don't complain customField is not defined on Request type - if (typeof (req as any).customField !== 'undefined') { + // @ts-expect-error customField property is not defined on request object + if (typeof req.customField !== 'undefined') { throw new Error('Request object was mutated'); } return t.next(); }); router.get({ path: '/', validate: false }, (context, req, res) => - // don't complain customField is not defined on Request type - res.ok({ body: { customField: String((req as any).customField) } }) + // @ts-expect-error customField property is not defined on request object + res.ok({ body: { customField: String(req.customField) } }) ); await server.start(); @@ -664,7 +814,7 @@ describe('Auth', () => { it.skip('is the only place with access to the authorization header', async () => { const { - registerOnPreAuth, + registerOnPreRouting, registerAuth, registerOnPostAuth, server: innerServer, @@ -672,9 +822,9 @@ describe('Auth', () => { } = await server.setup(setupDeps); const router = createRouter('/'); - let fromRegisterOnPreAuth; - await registerOnPreAuth((req, res, toolkit) => { - fromRegisterOnPreAuth = req.headers.authorization; + let fromregisterOnPreRouting; + await registerOnPreRouting((req, res, toolkit) => { + fromregisterOnPreRouting = req.headers.authorization; return toolkit.next(); }); @@ -701,7 +851,7 @@ describe('Auth', () => { const token = 'Basic: user:password'; await supertest(innerServer.listener).get('/').set('Authorization', token).expect(200); - expect(fromRegisterOnPreAuth).toEqual({}); + expect(fromregisterOnPreRouting).toEqual({}); expect(fromRegisterAuth).toEqual({ authorization: token }); expect(fromRegisterOnPostAuth).toEqual({}); expect(fromRouteHandler).toEqual({}); @@ -1137,3 +1287,135 @@ describe('OnPreResponse', () => { expect(requestBody).toStrictEqual({}); }); }); + +describe('run interceptors in the right order', () => { + it('with Auth registered', async () => { + const { + registerOnPreRouting, + registerOnPreAuth, + registerAuth, + registerOnPostAuth, + registerOnPreResponse, + server: innerServer, + createRouter, + } = await server.setup(setupDeps); + + const router = createRouter('/'); + + const executionOrder: string[] = []; + registerOnPreRouting((req, res, t) => { + executionOrder.push('onPreRouting'); + return t.next(); + }); + registerOnPreAuth((req, res, t) => { + executionOrder.push('onPreAuth'); + return t.next(); + }); + registerAuth((req, res, t) => { + executionOrder.push('auth'); + return t.authenticated({}); + }); + registerOnPostAuth((req, res, t) => { + executionOrder.push('onPostAuth'); + return t.next(); + }); + registerOnPreResponse((req, res, t) => { + executionOrder.push('onPreResponse'); + return t.next(); + }); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' })); + + await server.start(); + + await supertest(innerServer.listener).get('/').expect(200); + expect(executionOrder).toEqual([ + 'onPreRouting', + 'onPreAuth', + 'auth', + 'onPostAuth', + 'onPreResponse', + ]); + }); + + it('with no Auth registered', async () => { + const { + registerOnPreRouting, + registerOnPreAuth, + registerOnPostAuth, + registerOnPreResponse, + server: innerServer, + createRouter, + } = await server.setup(setupDeps); + + const router = createRouter('/'); + + const executionOrder: string[] = []; + registerOnPreRouting((req, res, t) => { + executionOrder.push('onPreRouting'); + return t.next(); + }); + registerOnPreAuth((req, res, t) => { + executionOrder.push('onPreAuth'); + return t.next(); + }); + registerOnPostAuth((req, res, t) => { + executionOrder.push('onPostAuth'); + return t.next(); + }); + registerOnPreResponse((req, res, t) => { + executionOrder.push('onPreResponse'); + return t.next(); + }); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' })); + + await server.start(); + + await supertest(innerServer.listener).get('/').expect(200); + expect(executionOrder).toEqual(['onPreRouting', 'onPreAuth', 'onPostAuth', 'onPreResponse']); + }); + + it('when a user failed auth', async () => { + const { + registerOnPreRouting, + registerOnPreAuth, + registerOnPostAuth, + registerAuth, + registerOnPreResponse, + server: innerServer, + createRouter, + } = await server.setup(setupDeps); + + const router = createRouter('/'); + + const executionOrder: string[] = []; + registerOnPreRouting((req, res, t) => { + executionOrder.push('onPreRouting'); + return t.next(); + }); + registerOnPreAuth((req, res, t) => { + executionOrder.push('onPreAuth'); + return t.next(); + }); + registerAuth((req, res, t) => { + executionOrder.push('auth'); + return res.forbidden(); + }); + registerOnPostAuth((req, res, t) => { + executionOrder.push('onPostAuth'); + return t.next(); + }); + registerOnPreResponse((req, res, t) => { + executionOrder.push('onPreResponse'); + return t.next(); + }); + + router.get({ path: '/', validate: false }, (context, req, res) => res.ok({ body: 'ok' })); + + await server.start(); + + await supertest(innerServer.listener).get('/').expect(403); + expect(executionOrder).toEqual(['onPreRouting', 'onPreAuth', 'auth', 'onPreResponse']); + }); +}); diff --git a/src/core/server/http/lifecycle/on_pre_auth.ts b/src/core/server/http/lifecycle/on_pre_auth.ts index dc2ae6922fb94a..f76fe87fd14a3a 100644 --- a/src/core/server/http/lifecycle/on_pre_auth.ts +++ b/src/core/server/http/lifecycle/on_pre_auth.ts @@ -29,33 +29,21 @@ import { enum ResultType { next = 'next', - rewriteUrl = 'rewriteUrl', } interface Next { type: ResultType.next; } -interface RewriteUrl { - type: ResultType.rewriteUrl; - url: string; -} - -type OnPreAuthResult = Next | RewriteUrl; +type OnPreAuthResult = Next; const preAuthResult = { next(): OnPreAuthResult { return { type: ResultType.next }; }, - rewriteUrl(url: string): OnPreAuthResult { - return { type: ResultType.rewriteUrl, url }; - }, isNext(result: OnPreAuthResult): result is Next { return result && result.type === ResultType.next; }, - isRewriteUrl(result: OnPreAuthResult): result is RewriteUrl { - return result && result.type === ResultType.rewriteUrl; - }, }; /** @@ -65,13 +53,10 @@ const preAuthResult = { export interface OnPreAuthToolkit { /** To pass request to the next handler */ next: () => OnPreAuthResult; - /** Rewrite requested resources url before is was authenticated and routed to a handler */ - rewriteUrl: (url: string) => OnPreAuthResult; } const toolkit: OnPreAuthToolkit = { next: preAuthResult.next, - rewriteUrl: preAuthResult.rewriteUrl, }; /** @@ -88,9 +73,9 @@ export type OnPreAuthHandler = ( * @public * Adopt custom request interceptor to Hapi lifecycle system. * @param fn - an extension point allowing to perform custom logic for - * incoming HTTP requests. + * incoming HTTP requests before a user has been authenticated. */ -export function adoptToHapiOnPreAuthFormat(fn: OnPreAuthHandler, log: Logger) { +export function adoptToHapiOnPreAuth(fn: OnPreAuthHandler, log: Logger) { return async function interceptPreAuthRequest( request: Request, responseToolkit: HapiResponseToolkit @@ -107,13 +92,6 @@ export function adoptToHapiOnPreAuthFormat(fn: OnPreAuthHandler, log: Logger) { return responseToolkit.continue; } - if (preAuthResult.isRewriteUrl(result)) { - const { url } = result; - request.setUrl(url); - // We should update raw request as well since it can be proxied to the old platform - request.raw.req.url = url; - return responseToolkit.continue; - } throw new Error( `Unexpected result from OnPreAuth. Expected OnPreAuthResult or KibanaResponse, but given: ${result}.` ); diff --git a/src/core/server/http/lifecycle/on_pre_response.ts b/src/core/server/http/lifecycle/on_pre_response.ts index 9c8c6fba690d18..4d1b53313a51fd 100644 --- a/src/core/server/http/lifecycle/on_pre_response.ts +++ b/src/core/server/http/lifecycle/on_pre_response.ts @@ -64,7 +64,7 @@ const preResponseResult = { }; /** - * A tool set defining an outcome of OnPreAuth interceptor for incoming request. + * A tool set defining an outcome of OnPreResponse interceptor for incoming request. * @public */ export interface OnPreResponseToolkit { @@ -77,7 +77,7 @@ const toolkit: OnPreResponseToolkit = { }; /** - * See {@link OnPreAuthToolkit}. + * See {@link OnPreRoutingToolkit}. * @public */ export type OnPreResponseHandler = ( diff --git a/src/core/server/http/lifecycle/on_pre_routing.ts b/src/core/server/http/lifecycle/on_pre_routing.ts new file mode 100644 index 00000000000000..e62eb54f2398f5 --- /dev/null +++ b/src/core/server/http/lifecycle/on_pre_routing.ts @@ -0,0 +1,125 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { Lifecycle, Request, ResponseToolkit as HapiResponseToolkit } from 'hapi'; +import { Logger } from '../../logging'; +import { + HapiResponseAdapter, + KibanaRequest, + KibanaResponse, + lifecycleResponseFactory, + LifecycleResponseFactory, +} from '../router'; + +enum ResultType { + next = 'next', + rewriteUrl = 'rewriteUrl', +} + +interface Next { + type: ResultType.next; +} + +interface RewriteUrl { + type: ResultType.rewriteUrl; + url: string; +} + +type OnPreRoutingResult = Next | RewriteUrl; + +const preRoutingResult = { + next(): OnPreRoutingResult { + return { type: ResultType.next }; + }, + rewriteUrl(url: string): OnPreRoutingResult { + return { type: ResultType.rewriteUrl, url }; + }, + isNext(result: OnPreRoutingResult): result is Next { + return result && result.type === ResultType.next; + }, + isRewriteUrl(result: OnPreRoutingResult): result is RewriteUrl { + return result && result.type === ResultType.rewriteUrl; + }, +}; + +/** + * @public + * A tool set defining an outcome of OnPreRouting interceptor for incoming request. + */ +export interface OnPreRoutingToolkit { + /** To pass request to the next handler */ + next: () => OnPreRoutingResult; + /** Rewrite requested resources url before is was authenticated and routed to a handler */ + rewriteUrl: (url: string) => OnPreRoutingResult; +} + +const toolkit: OnPreRoutingToolkit = { + next: preRoutingResult.next, + rewriteUrl: preRoutingResult.rewriteUrl, +}; + +/** + * See {@link OnPreRoutingToolkit}. + * @public + */ +export type OnPreRoutingHandler = ( + request: KibanaRequest, + response: LifecycleResponseFactory, + toolkit: OnPreRoutingToolkit +) => OnPreRoutingResult | KibanaResponse | Promise; + +/** + * @public + * Adopt custom request interceptor to Hapi lifecycle system. + * @param fn - an extension point allowing to perform custom logic for + * incoming HTTP requests. + */ +export function adoptToHapiOnRequest(fn: OnPreRoutingHandler, log: Logger) { + return async function interceptPreRoutingRequest( + request: Request, + responseToolkit: HapiResponseToolkit + ): Promise { + const hapiResponseAdapter = new HapiResponseAdapter(responseToolkit); + + try { + const result = await fn(KibanaRequest.from(request), lifecycleResponseFactory, toolkit); + if (result instanceof KibanaResponse) { + return hapiResponseAdapter.handle(result); + } + + if (preRoutingResult.isNext(result)) { + return responseToolkit.continue; + } + + if (preRoutingResult.isRewriteUrl(result)) { + const { url } = result; + request.setUrl(url); + // We should update raw request as well since it can be proxied to the old platform + request.raw.req.url = url; + return responseToolkit.continue; + } + throw new Error( + `Unexpected result from OnPreRouting. Expected OnPreRoutingResult or KibanaResponse, but given: ${result}.` + ); + } catch (error) { + log.error(error); + return hapiResponseAdapter.toInternalError(); + } + }; +} diff --git a/src/core/server/http/types.ts b/src/core/server/http/types.ts index 241af1a3020cba..3df098a1df00d6 100644 --- a/src/core/server/http/types.ts +++ b/src/core/server/http/types.ts @@ -25,6 +25,7 @@ import { HttpServerSetup } from './http_server'; import { SessionStorageCookieOptions } from './cookie_session_storage'; import { SessionStorageFactory } from './session_storage'; import { AuthenticationHandler } from './lifecycle/auth'; +import { OnPreRoutingHandler } from './lifecycle/on_pre_routing'; import { OnPreAuthHandler } from './lifecycle/on_pre_auth'; import { OnPostAuthHandler } from './lifecycle/on_post_auth'; import { OnPreResponseHandler } from './lifecycle/on_pre_response'; @@ -145,15 +146,26 @@ export interface HttpServiceSetup { ) => Promise>; /** - * To define custom logic to perform for incoming requests. + * To define custom logic to perform for incoming requests before server performs a route lookup. * * @remarks - * Runs the handler before Auth interceptor performs a check that user has access to requested resources, so it's the - * only place when you can forward a request to another URL right on the server. - * Can register any number of registerOnPostAuth, which are called in sequence + * It's the only place when you can forward a request to another URL right on the server. + * Can register any number of registerOnPreRouting, which are called in sequence + * (from the first registered to the last). See {@link OnPreRoutingHandler}. + * + * @param handler {@link OnPreRoutingHandler} - function to call. + */ + registerOnPreRouting: (handler: OnPreRoutingHandler) => void; + + /** + * To define custom logic to perform for incoming requests before + * the Auth interceptor performs a check that user has access to requested resources. + * + * @remarks + * Can register any number of registerOnPreAuth, which are called in sequence * (from the first registered to the last). See {@link OnPreAuthHandler}. * - * @param handler {@link OnPreAuthHandler} - function to call. + * @param handler {@link OnPreRoutingHandler} - function to call. */ registerOnPreAuth: (handler: OnPreAuthHandler) => void; @@ -170,13 +182,11 @@ export interface HttpServiceSetup { registerAuth: (handler: AuthenticationHandler) => void; /** - * To define custom logic to perform for incoming requests. + * To define custom logic after Auth interceptor did make sure a user has access to the requested resource. * * @remarks - * Runs the handler after Auth interceptor - * did make sure a user has access to the requested resource. * The auth state is available at stage via http.auth.get(..) - * Can register any number of registerOnPreAuth, which are called in sequence + * Can register any number of registerOnPostAuth, which are called in sequence * (from the first registered to the last). See {@link OnPostAuthHandler}. * * @param handler {@link OnPostAuthHandler} - function to call. diff --git a/src/core/server/index.ts b/src/core/server/index.ts index dcaa5f23672149..706ec88c6ebfda 100644 --- a/src/core/server/index.ts +++ b/src/core/server/index.ts @@ -148,6 +148,8 @@ export { LegacyRequest, OnPreAuthHandler, OnPreAuthToolkit, + OnPreRoutingHandler, + OnPreRoutingToolkit, OnPostAuthHandler, OnPostAuthToolkit, OnPreResponseHandler, diff --git a/src/core/server/legacy/legacy_service.ts b/src/core/server/legacy/legacy_service.ts index 6b34a4eb58319a..fada40e773f12b 100644 --- a/src/core/server/legacy/legacy_service.ts +++ b/src/core/server/legacy/legacy_service.ts @@ -301,6 +301,7 @@ export class LegacyService implements CoreService { ), createRouter: () => router, resources: setupDeps.core.httpResources.createRegistrar(router), + registerOnPreRouting: setupDeps.core.http.registerOnPreRouting, registerOnPreAuth: setupDeps.core.http.registerOnPreAuth, registerAuth: setupDeps.core.http.registerAuth, registerOnPostAuth: setupDeps.core.http.registerOnPostAuth, diff --git a/src/core/server/plugins/plugin_context.ts b/src/core/server/plugins/plugin_context.ts index a6dd13a12b5278..c17b8df8bb52c0 100644 --- a/src/core/server/plugins/plugin_context.ts +++ b/src/core/server/plugins/plugin_context.ts @@ -157,6 +157,7 @@ export function createPluginSetupContext( ), createRouter: () => router, resources: deps.httpResources.createRegistrar(router), + registerOnPreRouting: deps.http.registerOnPreRouting, registerOnPreAuth: deps.http.registerOnPreAuth, registerAuth: deps.http.registerAuth, registerOnPostAuth: deps.http.registerOnPostAuth, diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 3d3e1905577d91..886544a4df317f 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -811,6 +811,7 @@ export interface HttpServiceSetup { registerOnPostAuth: (handler: OnPostAuthHandler) => void; registerOnPreAuth: (handler: OnPreAuthHandler) => void; registerOnPreResponse: (handler: OnPreResponseHandler) => void; + registerOnPreRouting: (handler: OnPreRoutingHandler) => void; registerRouteHandlerContext: (contextName: T, provider: RequestHandlerContextProvider) => RequestHandlerContextContainer; } @@ -1536,7 +1537,6 @@ export type OnPreAuthHandler = (request: KibanaRequest, response: LifecycleRespo // @public export interface OnPreAuthToolkit { next: () => OnPreAuthResult; - rewriteUrl: (url: string) => OnPreAuthResult; } // @public @@ -1560,6 +1560,17 @@ export interface OnPreResponseToolkit { next: (responseExtensions?: OnPreResponseExtensions) => OnPreResponseResult; } +// Warning: (ae-forgotten-export) The symbol "OnPreRoutingResult" needs to be exported by the entry point index.d.ts +// +// @public +export type OnPreRoutingHandler = (request: KibanaRequest, response: LifecycleResponseFactory, toolkit: OnPreRoutingToolkit) => OnPreRoutingResult | KibanaResponse | Promise; + +// @public +export interface OnPreRoutingToolkit { + next: () => OnPreRoutingResult; + rewriteUrl: (url: string) => OnPreRoutingResult; +} + // @public export interface OpsMetrics { concurrent_connections: OpsServerMetrics['concurrent_connections']; 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 18e9da25576eba..4b3a5d662f12de 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 @@ -5,7 +5,7 @@ */ import { KibanaRequest, - OnPreAuthToolkit, + OnPreRoutingToolkit, LifecycleResponseFactory, CoreSetup, } from 'src/core/server'; @@ -18,10 +18,10 @@ export interface OnRequestInterceptorDeps { http: CoreSetup['http']; } export function initSpacesOnRequestInterceptor({ http }: OnRequestInterceptorDeps) { - http.registerOnPreAuth(async function spacesOnPreAuthHandler( + http.registerOnPreRouting(async function spacesOnPreRoutingHandler( request: KibanaRequest, response: LifecycleResponseFactory, - toolkit: OnPreAuthToolkit + toolkit: OnPreRoutingToolkit ) { const serverBasePath = http.basePath.serverBasePath; const path = request.url.pathname;