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:
Mikhail Shustov 2019-06-26 10:04:34 +02:00 committed by GitHub
parent 8ec14e07ae
commit 484351bdac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 35 additions and 123 deletions

View file

@ -1,22 +0,0 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
[Home](./index.md) &gt; [kibana-plugin-server](./kibana-plugin-server.md) &gt; [KibanaRequest](./kibana-plugin-server.kibanarequest.md) &gt; [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>`

View file

@ -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.

View file

@ -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&lt;KibanaRequestRoute&gt;</code> | | | [route](./kibana-plugin-server.kibanarequest.route.md) | | <code>RecursiveReadonly&lt;KibanaRequestRoute&gt;</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

View file

@ -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);

View file

@ -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 });

View file

@ -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',
}); });

View file

@ -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 {

View file

@ -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;