mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com> Co-authored-by: Josh Dover <me@joshdover.com> Co-authored-by: Mikhail Shustov <restrry@gmail.com>
This commit is contained in:
parent
2f10543936
commit
3c7a9e1bfb
29 changed files with 630 additions and 122 deletions
|
@ -88,8 +88,9 @@ async (context, request, response) => {
|
|||
| [csp](./kibana-plugin-core-server.httpservicesetup.csp.md) | <code>ICspConfig</code> | The CSP config used for Kibana. |
|
||||
| [getServerInfo](./kibana-plugin-core-server.httpservicesetup.getserverinfo.md) | <code>() => HttpServerInfo</code> | Provides common [information](./kibana-plugin-core-server.httpserverinfo.md) about the running http server. |
|
||||
| [registerAuth](./kibana-plugin-core-server.httpservicesetup.registerauth.md) | <code>(handler: AuthenticationHandler) => void</code> | To define custom authentication and/or authorization mechanism for incoming requests. |
|
||||
| [registerOnPostAuth](./kibana-plugin-core-server.httpservicesetup.registeronpostauth.md) | <code>(handler: OnPostAuthHandler) => void</code> | To define custom logic to perform for incoming requests. |
|
||||
| [registerOnPreAuth](./kibana-plugin-core-server.httpservicesetup.registeronpreauth.md) | <code>(handler: OnPreAuthHandler) => void</code> | To define custom logic to perform for incoming requests. |
|
||||
| [registerOnPostAuth](./kibana-plugin-core-server.httpservicesetup.registeronpostauth.md) | <code>(handler: OnPostAuthHandler) => void</code> | 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) | <code>(handler: OnPreAuthHandler) => void</code> | 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) | <code>(handler: OnPreResponseHandler) => void</code> | To define custom logic to perform for the server response. |
|
||||
| [registerOnPreRouting](./kibana-plugin-core-server.httpservicesetup.registeronprerouting.md) | <code>(handler: OnPreRoutingHandler) => void</code> | To define custom logic to perform for incoming requests before server performs a route lookup. |
|
||||
| [registerRouteHandlerContext](./kibana-plugin-core-server.httpservicesetup.registerroutehandlercontext.md) | <code><T extends keyof RequestHandlerContext>(contextName: T, provider: RequestHandlerContextProvider<T>) => RequestHandlerContextContainer</code> | Register a context provider for a route handler. |
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
@ -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)<!-- -->.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
@ -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)<!-- -->.
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```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)<!-- -->.
|
||||
|
|
@ -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 <code>plugin</code> export at the root of a plugin's <code>server</code> 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. |
|
||||
|
|
|
@ -17,5 +17,4 @@ export interface OnPreAuthToolkit
|
|||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [next](./kibana-plugin-core-server.onpreauthtoolkit.next.md) | <code>() => OnPreAuthResult</code> | To pass request to the next handler |
|
||||
| [rewriteUrl](./kibana-plugin-core-server.onpreauthtoolkit.rewriteurl.md) | <code>(url: string) => OnPreAuthResult</code> | Rewrite requested resources url before is was authenticated and routed to a handler |
|
||||
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rewriteUrl: (url: string) => OnPreAuthResult;
|
||||
```
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## OnPreResponseHandler type
|
||||
|
||||
See [OnPreAuthToolkit](./kibana-plugin-core-server.onpreauthtoolkit.md)<!-- -->.
|
||||
See [OnPreRoutingToolkit](./kibana-plugin-core-server.onpreroutingtoolkit.md)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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)<!-- -->.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type OnPreRoutingHandler = (request: KibanaRequest, response: LifecycleResponseFactory, toolkit: OnPreRoutingToolkit) => OnPreRoutingResult | KibanaResponse | Promise<OnPreRoutingResult | KibanaResponse>;
|
||||
```
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface OnPreRoutingToolkit
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| [next](./kibana-plugin-core-server.onpreroutingtoolkit.next.md) | <code>() => OnPreRoutingResult</code> | To pass request to the next handler |
|
||||
| [rewriteUrl](./kibana-plugin-core-server.onpreroutingtoolkit.rewriteurl.md) | <code>(url: string) => OnPreRoutingResult</code> | Rewrite requested resources url before is was authenticated and routed to a handler |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
next: () => OnPreRoutingResult;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[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
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rewriteUrl: (url: string) => OnPreRoutingResult;
|
||||
```
|
|
@ -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<P = any, Q = any, B = any> {
|
||||
auth?: { isAuthenticated: boolean };
|
||||
|
@ -161,7 +161,7 @@ const createLifecycleResponseFactoryMock = (): jest.Mocked<LifecycleResponseFact
|
|||
customError: jest.fn(),
|
||||
});
|
||||
|
||||
type ToolkitMock = jest.Mocked<OnPreResponseToolkit & OnPostAuthToolkit & OnPreAuthToolkit>;
|
||||
type ToolkitMock = jest.Mocked<OnPreResponseToolkit & OnPostAuthToolkit & OnPreRoutingToolkit>;
|
||||
|
||||
const createToolkitMock = (): ToolkitMock => {
|
||||
return {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: <T>(cookieOptions: SessionStorageCookieOptions<T>) =>
|
||||
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) {
|
||||
|
|
|
@ -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<Server>,
|
||||
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<OnPreAuthToolkit> => ({
|
||||
const createOnPreAuthToolkitMock = (): jest.Mocked<OnPreRoutingToolkit> => ({
|
||||
next: jest.fn(),
|
||||
rewriteUrl: jest.fn(),
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
|
|
@ -57,6 +57,188 @@ interface StorageData {
|
|||
expires: number;
|
||||
}
|
||||
|
||||
describe('OnPreRouting', () => {
|
||||
it('supports registering a request interceptor', async () => {
|
||||
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[] = [];
|
||||
registerOnPreRouting((req, res, t) => {
|
||||
callingOrder.push('first');
|
||||
return t.next();
|
||||
});
|
||||
|
||||
registerOnPreRouting((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 request forwarding to specified url', async () => {
|
||||
const { registerOnPreRouting, server: innerServer, createRouter } = await server.setup(
|
||||
setupDeps
|
||||
);
|
||||
const router = createRouter('/');
|
||||
|
||||
router.get({ path: '/initial', validate: false }, (context, req, res) =>
|
||||
res.ok({ body: 'initial' })
|
||||
);
|
||||
router.get({ path: '/redirectUrl', validate: false }, (context, req, res) =>
|
||||
res.ok({ body: 'redirected' })
|
||||
);
|
||||
|
||||
let urlBeforeForwarding;
|
||||
registerOnPreRouting((req, res, t) => {
|
||||
urlBeforeForwarding = ensureRawRequest(req).raw.req.url;
|
||||
return t.rewriteUrl('/redirectUrl');
|
||||
});
|
||||
|
||||
let urlAfterForwarding;
|
||||
registerOnPreRouting((req, res, t) => {
|
||||
// used by legacy platform
|
||||
urlAfterForwarding = ensureRawRequest(req).raw.req.url;
|
||||
return t.next();
|
||||
});
|
||||
|
||||
await server.start();
|
||||
|
||||
await supertest(innerServer.listener).get('/initial').expect(200, 'redirected');
|
||||
|
||||
expect(urlBeforeForwarding).toBe('/initial');
|
||||
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);
|
||||
|
@ -81,38 +263,6 @@ describe('OnPreAuth', () => {
|
|||
expect(callingOrder).toEqual(['first', 'second']);
|
||||
});
|
||||
|
||||
it('supports request forwarding to specified url', async () => {
|
||||
const { registerOnPreAuth, server: innerServer, createRouter } = await server.setup(setupDeps);
|
||||
const router = createRouter('/');
|
||||
|
||||
router.get({ path: '/initial', validate: false }, (context, req, res) =>
|
||||
res.ok({ body: 'initial' })
|
||||
);
|
||||
router.get({ path: '/redirectUrl', validate: false }, (context, req, res) =>
|
||||
res.ok({ body: 'redirected' })
|
||||
);
|
||||
|
||||
let urlBeforeForwarding;
|
||||
registerOnPreAuth((req, res, t) => {
|
||||
urlBeforeForwarding = ensureRawRequest(req).raw.req.url;
|
||||
return t.rewriteUrl('/redirectUrl');
|
||||
});
|
||||
|
||||
let urlAfterForwarding;
|
||||
registerOnPreAuth((req, res, t) => {
|
||||
// used by legacy platform
|
||||
urlAfterForwarding = ensureRawRequest(req).raw.req.url;
|
||||
return t.next();
|
||||
});
|
||||
|
||||
await server.start();
|
||||
|
||||
await supertest(innerServer.listener).get('/initial').expect(200, 'redirected');
|
||||
|
||||
expect(urlBeforeForwarding).toBe('/initial');
|
||||
expect(urlAfterForwarding).toBe('/redirectUrl');
|
||||
});
|
||||
|
||||
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']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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}.`
|
||||
);
|
||||
|
|
|
@ -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 = (
|
||||
|
|
125
src/core/server/http/lifecycle/on_pre_routing.ts
Normal file
125
src/core/server/http/lifecycle/on_pre_routing.ts
Normal file
|
@ -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<OnPreRoutingResult | KibanaResponse>;
|
||||
|
||||
/**
|
||||
* @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<Lifecycle.ReturnValue> {
|
||||
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();
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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<SessionStorageFactory<T>>;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
|
@ -148,6 +148,8 @@ export {
|
|||
LegacyRequest,
|
||||
OnPreAuthHandler,
|
||||
OnPreAuthToolkit,
|
||||
OnPreRoutingHandler,
|
||||
OnPreRoutingToolkit,
|
||||
OnPostAuthHandler,
|
||||
OnPostAuthToolkit,
|
||||
OnPreResponseHandler,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -157,6 +157,7 @@ export function createPluginSetupContext<TPlugin, TPluginDependencies>(
|
|||
),
|
||||
createRouter: () => router,
|
||||
resources: deps.httpResources.createRegistrar(router),
|
||||
registerOnPreRouting: deps.http.registerOnPreRouting,
|
||||
registerOnPreAuth: deps.http.registerOnPreAuth,
|
||||
registerAuth: deps.http.registerAuth,
|
||||
registerOnPostAuth: deps.http.registerOnPostAuth,
|
||||
|
|
|
@ -811,6 +811,7 @@ export interface HttpServiceSetup {
|
|||
registerOnPostAuth: (handler: OnPostAuthHandler) => void;
|
||||
registerOnPreAuth: (handler: OnPreAuthHandler) => void;
|
||||
registerOnPreResponse: (handler: OnPreResponseHandler) => void;
|
||||
registerOnPreRouting: (handler: OnPreRoutingHandler) => void;
|
||||
registerRouteHandlerContext: <T extends keyof RequestHandlerContext>(contextName: T, provider: RequestHandlerContextProvider<T>) => 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<OnPreRoutingResult | KibanaResponse>;
|
||||
|
||||
// @public
|
||||
export interface OnPreRoutingToolkit {
|
||||
next: () => OnPreRoutingResult;
|
||||
rewriteUrl: (url: string) => OnPreRoutingResult;
|
||||
}
|
||||
|
||||
// @public
|
||||
export interface OpsMetrics {
|
||||
concurrent_connections: OpsServerMetrics['concurrent_connections'];
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue