KibanaRequest provides headers as a property. (#39506)
* use property instead of method. not all header names are known * fix tag name and re-generate docs
This commit is contained in:
parent
8ec14e07ae
commit
484351bdac
8 changed files with 35 additions and 123 deletions
|
@ -1,22 +0,0 @@
|
||||||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
|
||||||
|
|
||||||
[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [KibanaRequest](./kibana-plugin-server.kibanarequest.md) > [getFilteredHeaders](./kibana-plugin-server.kibanarequest.getfilteredheaders.md)
|
|
||||||
|
|
||||||
## KibanaRequest.getFilteredHeaders() method
|
|
||||||
|
|
||||||
<b>Signature:</b>
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
getFilteredHeaders(headersToKeep: string[]): Pick<Record<string, string | string[] | undefined>, string>;
|
|
||||||
```
|
|
||||||
|
|
||||||
## Parameters
|
|
||||||
|
|
||||||
| Parameter | Type | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| headersToKeep | <code>string[]</code> | |
|
|
||||||
|
|
||||||
<b>Returns:</b>
|
|
||||||
|
|
||||||
`Pick<Record<string, string | string[] | undefined>, string>`
|
|
||||||
|
|
|
@ -4,10 +4,15 @@
|
||||||
|
|
||||||
## KibanaRequest.headers property
|
## KibanaRequest.headers property
|
||||||
|
|
||||||
This property will be removed in future version of this class, please use the `getFilteredHeaders` method instead
|
Readonly copy of incoming request headers.
|
||||||
|
|
||||||
<b>Signature:</b>
|
<b>Signature:</b>
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
readonly headers: Headers;
|
readonly headers: Headers;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Remarks
|
||||||
|
|
||||||
|
This property will contain a `filtered` copy of request headers.
|
||||||
|
|
||||||
|
|
|
@ -23,19 +23,9 @@ export declare class KibanaRequest<Params = unknown, Query = unknown, Body = unk
|
||||||
| Property | Modifiers | Type | Description |
|
| Property | Modifiers | Type | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| [body](./kibana-plugin-server.kibanarequest.body.md) | | <code>Body</code> | |
|
| [body](./kibana-plugin-server.kibanarequest.body.md) | | <code>Body</code> | |
|
||||||
| [headers](./kibana-plugin-server.kibanarequest.headers.md) | | <code>Headers</code> | This property will be removed in future version of this class, please use the <code>getFilteredHeaders</code> method instead |
|
| [headers](./kibana-plugin-server.kibanarequest.headers.md) | | <code>Headers</code> | Readonly copy of incoming request headers. |
|
||||||
| [params](./kibana-plugin-server.kibanarequest.params.md) | | <code>Params</code> | |
|
| [params](./kibana-plugin-server.kibanarequest.params.md) | | <code>Params</code> | |
|
||||||
| [query](./kibana-plugin-server.kibanarequest.query.md) | | <code>Query</code> | |
|
| [query](./kibana-plugin-server.kibanarequest.query.md) | | <code>Query</code> | |
|
||||||
| [route](./kibana-plugin-server.kibanarequest.route.md) | | <code>RecursiveReadonly<KibanaRequestRoute></code> | |
|
| [route](./kibana-plugin-server.kibanarequest.route.md) | | <code>RecursiveReadonly<KibanaRequestRoute></code> | |
|
||||||
| [url](./kibana-plugin-server.kibanarequest.url.md) | | <code>Url</code> | |
|
| [url](./kibana-plugin-server.kibanarequest.url.md) | | <code>Url</code> | |
|
||||||
|
|
||||||
## Methods
|
|
||||||
|
|
||||||
| Method | Modifiers | Description |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| [getFilteredHeaders(headersToKeep)](./kibana-plugin-server.kibanarequest.getfilteredheaders.md) | | |
|
|
||||||
|
|
||||||
## Remarks
|
|
||||||
|
|
||||||
The `headers` property will be deprecated and removed in future versions of this class. Please use the `getFilteredHeaders` method to acesss the list of headers available
|
|
||||||
|
|
||||||
|
|
|
@ -406,35 +406,6 @@ test('handles deleting', async () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('filtered headers', async () => {
|
|
||||||
expect.assertions(1);
|
|
||||||
|
|
||||||
const router = new Router('/foo');
|
|
||||||
|
|
||||||
let filteredHeaders: any;
|
|
||||||
|
|
||||||
router.get({ path: '/', validate: false }, (req, res) => {
|
|
||||||
filteredHeaders = req.getFilteredHeaders(['x-kibana-foo', 'host']);
|
|
||||||
|
|
||||||
return res.noContent();
|
|
||||||
});
|
|
||||||
|
|
||||||
const { registerRouter, server: innerServer } = await server.setup(config);
|
|
||||||
registerRouter(router);
|
|
||||||
|
|
||||||
await server.start();
|
|
||||||
|
|
||||||
await supertest(innerServer.listener)
|
|
||||||
.get('/foo/?bar=quux')
|
|
||||||
.set('x-kibana-foo', 'bar')
|
|
||||||
.set('x-kibana-bar', 'quux');
|
|
||||||
|
|
||||||
expect(filteredHeaders).toEqual({
|
|
||||||
host: `127.0.0.1:${config.port}`,
|
|
||||||
'x-kibana-foo': 'bar',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with `basepath: /bar` and `rewriteBasePath: false`', () => {
|
describe('with `basepath: /bar` and `rewriteBasePath: false`', () => {
|
||||||
let configWithBasePath: HttpConfig;
|
let configWithBasePath: HttpConfig;
|
||||||
let innerServerListener: Server;
|
let innerServerListener: Server;
|
||||||
|
@ -756,7 +727,7 @@ describe('#registerAuth', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('is the only place with access to the authorization header', async () => {
|
it.skip('is the only place with access to the authorization header', async () => {
|
||||||
const token = 'Basic: user:password';
|
const token = 'Basic: user:password';
|
||||||
const {
|
const {
|
||||||
registerAuth,
|
registerAuth,
|
||||||
|
@ -768,26 +739,26 @@ describe('#registerAuth', () => {
|
||||||
|
|
||||||
let fromRegisterOnPreAuth;
|
let fromRegisterOnPreAuth;
|
||||||
await registerOnPreAuth((req, t) => {
|
await registerOnPreAuth((req, t) => {
|
||||||
fromRegisterOnPreAuth = req.getFilteredHeaders(['authorization']);
|
fromRegisterOnPreAuth = req.headers.authorization;
|
||||||
return t.next();
|
return t.next();
|
||||||
});
|
});
|
||||||
|
|
||||||
let fromRegisterAuth;
|
let fromRegisterAuth;
|
||||||
await registerAuth((req, t) => {
|
await registerAuth((req, t) => {
|
||||||
fromRegisterAuth = req.getFilteredHeaders(['authorization']);
|
fromRegisterAuth = req.headers.authorization;
|
||||||
return t.authenticated();
|
return t.authenticated();
|
||||||
}, cookieOptions);
|
}, cookieOptions);
|
||||||
|
|
||||||
let fromRegisterOnPostAuth;
|
let fromRegisterOnPostAuth;
|
||||||
await registerOnPostAuth((req, t) => {
|
await registerOnPostAuth((req, t) => {
|
||||||
fromRegisterOnPostAuth = req.getFilteredHeaders(['authorization']);
|
fromRegisterOnPostAuth = req.headers.authorization;
|
||||||
return t.next();
|
return t.next();
|
||||||
});
|
});
|
||||||
|
|
||||||
let fromRouteHandler;
|
let fromRouteHandler;
|
||||||
const router = new Router('');
|
const router = new Router('');
|
||||||
router.get({ path: '/', validate: false }, (req, res) => {
|
router.get({ path: '/', validate: false }, (req, res) => {
|
||||||
fromRouteHandler = req.getFilteredHeaders(['authorization']);
|
fromRouteHandler = req.headers.authorization;
|
||||||
return res.ok({ content: 'ok' });
|
return res.ok({ content: 'ok' });
|
||||||
});
|
});
|
||||||
registerRouter(router);
|
registerRouter(router);
|
||||||
|
|
|
@ -59,8 +59,7 @@ describe('http service', () => {
|
||||||
it('runs auth for legacy routes and proxy request to legacy server route handlers', async () => {
|
it('runs auth for legacy routes and proxy request to legacy server route handlers', async () => {
|
||||||
const { http } = await root.setup();
|
const { http } = await root.setup();
|
||||||
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
||||||
const headers = req.getFilteredHeaders(['authorization']);
|
if (req.headers.authorization) {
|
||||||
if (headers.authorization) {
|
|
||||||
const user = { id: '42' };
|
const user = { id: '42' };
|
||||||
const sessionStorage = sessionStorageFactory.asScoped(req);
|
const sessionStorage = sessionStorageFactory.asScoped(req);
|
||||||
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
||||||
|
@ -90,8 +89,7 @@ describe('http service', () => {
|
||||||
const token = 'Basic: name:password';
|
const token = 'Basic: name:password';
|
||||||
const { http } = await root.setup();
|
const { http } = await root.setup();
|
||||||
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
||||||
const headers = req.getFilteredHeaders(['authorization']);
|
if (req.headers.authorization) {
|
||||||
if (headers.authorization) {
|
|
||||||
const user = { id: '42' };
|
const user = { id: '42' };
|
||||||
const sessionStorage = sessionStorageFactory.asScoped(req);
|
const sessionStorage = sessionStorageFactory.asScoped(req);
|
||||||
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
||||||
|
@ -129,8 +127,7 @@ describe('http service', () => {
|
||||||
|
|
||||||
const { http } = await root.setup();
|
const { http } = await root.setup();
|
||||||
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
|
||||||
const headers = req.getFilteredHeaders(['authorization']);
|
if (req.headers.authorization) {
|
||||||
if (headers.authorization) {
|
|
||||||
const sessionStorage = sessionStorageFactory.asScoped(req);
|
const sessionStorage = sessionStorageFactory.asScoped(req);
|
||||||
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
|
||||||
return t.authenticated({ state: user });
|
return t.authenticated({ state: user });
|
||||||
|
|
|
@ -30,41 +30,25 @@ describe('KibanaRequest', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getFilteredHeaders', () => {
|
describe('headers property', () => {
|
||||||
it('returns request headers', () => {
|
it('provides a frozen copy of request headers', () => {
|
||||||
|
const rawRequestHeaders = { custom: 'one' };
|
||||||
const request = httpServerMock.createRawRequest({
|
const request = httpServerMock.createRawRequest({
|
||||||
headers: { custom: 'one' },
|
headers: rawRequestHeaders,
|
||||||
});
|
});
|
||||||
const kibanaRequest = KibanaRequest.from(request);
|
const kibanaRequest = KibanaRequest.from(request);
|
||||||
expect(kibanaRequest.getFilteredHeaders(['custom'])).toEqual({
|
|
||||||
custom: 'one',
|
expect(kibanaRequest.headers).toEqual({ custom: 'one' });
|
||||||
});
|
expect(kibanaRequest.headers).not.toBe(rawRequestHeaders);
|
||||||
|
expect(Object.isFrozen(kibanaRequest.headers)).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('normalizes a header name', () => {
|
it.skip("doesn't expose authorization header by default", () => {
|
||||||
const request = httpServerMock.createRawRequest({
|
|
||||||
headers: { custom: 'one' },
|
|
||||||
});
|
|
||||||
const kibanaRequest = KibanaRequest.from(request);
|
|
||||||
expect(kibanaRequest.getFilteredHeaders(['CUSTOM'])).toEqual({
|
|
||||||
custom: 'one',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('returns an empty object is no headers were specified', () => {
|
|
||||||
const request = httpServerMock.createRawRequest({
|
|
||||||
headers: { custom: 'one' },
|
|
||||||
});
|
|
||||||
const kibanaRequest = KibanaRequest.from(request);
|
|
||||||
expect(kibanaRequest.getFilteredHeaders([])).toEqual({});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("doesn't expose authorization header by default", () => {
|
|
||||||
const request = httpServerMock.createRawRequest({
|
const request = httpServerMock.createRawRequest({
|
||||||
headers: { custom: 'one', authorization: 'token' },
|
headers: { custom: 'one', authorization: 'token' },
|
||||||
});
|
});
|
||||||
const kibanaRequest = KibanaRequest.from(request);
|
const kibanaRequest = KibanaRequest.from(request);
|
||||||
expect(kibanaRequest.getFilteredHeaders(['custom', 'authorization'])).toEqual({
|
expect(kibanaRequest.headers).toEqual({
|
||||||
custom: 'one',
|
custom: 'one',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -74,7 +58,7 @@ describe('KibanaRequest', () => {
|
||||||
headers: { custom: 'one', authorization: 'token' },
|
headers: { custom: 'one', authorization: 'token' },
|
||||||
});
|
});
|
||||||
const kibanaRequest = KibanaRequest.from(request, undefined, false);
|
const kibanaRequest = KibanaRequest.from(request, undefined, false);
|
||||||
expect(kibanaRequest.getFilteredHeaders(['custom', 'authorization'])).toEqual({
|
expect(kibanaRequest.headers).toEqual({
|
||||||
custom: 'one',
|
custom: 'one',
|
||||||
authorization: 'token',
|
authorization: 'token',
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,11 +18,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Url } from 'url';
|
import { Url } from 'url';
|
||||||
import { ObjectType, TypeOf } from '@kbn/config-schema';
|
|
||||||
import { Request } from 'hapi';
|
import { Request } from 'hapi';
|
||||||
|
|
||||||
|
import { ObjectType, TypeOf } from '@kbn/config-schema';
|
||||||
|
|
||||||
import { deepFreeze, RecursiveReadonly } from '../../../utils';
|
import { deepFreeze, RecursiveReadonly } from '../../../utils';
|
||||||
import { filterHeaders, Headers } from './headers';
|
import { Headers } from './headers';
|
||||||
import { RouteMethod, RouteSchemas, RouteConfigOptions } from './route';
|
import { RouteMethod, RouteSchemas, RouteConfigOptions } from './route';
|
||||||
|
|
||||||
const requestSymbol = Symbol('request');
|
const requestSymbol = Symbol('request');
|
||||||
|
@ -37,15 +38,8 @@ export interface KibanaRequestRoute {
|
||||||
options: Required<RouteConfigOptions>;
|
options: Required<RouteConfigOptions>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const secretHeaders = ['authorization'];
|
|
||||||
/**
|
/**
|
||||||
* Kibana specific abstraction for an incoming request.
|
* Kibana specific abstraction for an incoming request.
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* The `headers` property will be deprecated and removed in future versions
|
|
||||||
* of this class. Please use the `getFilteredHeaders` method to acesss the
|
|
||||||
* list of headers available
|
|
||||||
*
|
|
||||||
* @public
|
* @public
|
||||||
* */
|
* */
|
||||||
export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
||||||
|
@ -104,8 +98,9 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
||||||
public readonly url: Url;
|
public readonly url: Url;
|
||||||
public readonly route: RecursiveReadonly<KibanaRequestRoute>;
|
public readonly route: RecursiveReadonly<KibanaRequestRoute>;
|
||||||
/**
|
/**
|
||||||
* This property will be removed in future version of this class, please
|
* Readonly copy of incoming request headers.
|
||||||
* use the `getFilteredHeaders` method instead
|
* @remarks
|
||||||
|
* This property will contain a `filtered` copy of request headers.
|
||||||
*/
|
*/
|
||||||
public readonly headers: Headers;
|
public readonly headers: Headers;
|
||||||
|
|
||||||
|
@ -117,10 +112,12 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
||||||
readonly params: Params,
|
readonly params: Params,
|
||||||
readonly query: Query,
|
readonly query: Query,
|
||||||
readonly body: Body,
|
readonly body: Body,
|
||||||
|
// @ts-ignore we will use this flag as soon as http request proxy is supported in the core
|
||||||
|
// until that time we have to expose all the headers
|
||||||
private readonly withoutSecretHeaders: boolean
|
private readonly withoutSecretHeaders: boolean
|
||||||
) {
|
) {
|
||||||
this.url = request.url;
|
this.url = request.url;
|
||||||
this.headers = request.headers;
|
this.headers = deepFreeze({ ...request.headers });
|
||||||
|
|
||||||
// prevent Symbol exposure via Object.getOwnPropertySymbols()
|
// prevent Symbol exposure via Object.getOwnPropertySymbols()
|
||||||
Object.defineProperty(this, requestSymbol, {
|
Object.defineProperty(this, requestSymbol, {
|
||||||
|
@ -131,14 +128,6 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
||||||
this.route = deepFreeze(this.getRouteInfo());
|
this.route = deepFreeze(this.getRouteInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public getFilteredHeaders(headersToKeep: string[]) {
|
|
||||||
return filterHeaders(
|
|
||||||
this[requestSymbol].headers,
|
|
||||||
headersToKeep,
|
|
||||||
this.withoutSecretHeaders ? secretHeaders : []
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getRouteInfo() {
|
private getRouteInfo() {
|
||||||
const request = this[requestSymbol];
|
const request = this[requestSymbol];
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -189,8 +189,6 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
|
||||||
//
|
//
|
||||||
// @internal
|
// @internal
|
||||||
static from<P extends ObjectType, Q extends ObjectType, B extends ObjectType>(req: Request, routeSchemas?: RouteSchemas<P, Q, B>, withoutSecretHeaders?: boolean): KibanaRequest<P["type"], Q["type"], B["type"]>;
|
static from<P extends ObjectType, Q extends ObjectType, B extends ObjectType>(req: Request, routeSchemas?: RouteSchemas<P, Q, B>, withoutSecretHeaders?: boolean): KibanaRequest<P["type"], Q["type"], B["type"]>;
|
||||||
// (undocumented)
|
|
||||||
getFilteredHeaders(headersToKeep: string[]): Pick<Record<string, string | string[] | undefined>, string>;
|
|
||||||
readonly headers: Headers;
|
readonly headers: Headers;
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
readonly params: Params;
|
readonly params: Params;
|
||||||
|
|
Loading…
Reference in a new issue