Skip to content

Commit

Permalink
KibanaRequest provides headers as a property. (#39506)
Browse files Browse the repository at this point in the history
* use property instead of method. not all header names are known

* fix tag name and re-generate docs
  • Loading branch information
mshustov authored Jun 26, 2019
1 parent 8ec14e0 commit 484351b
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 122 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@

## 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>

```typescript
readonly headers: Headers;
```

## Remarks

This property will contain a `filtered` copy of request headers.

Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,9 @@ export declare class KibanaRequest<Params = unknown, Query = unknown, Body = unk
| Property | Modifiers | Type | Description |
| --- | --- | --- | --- |
| [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> | |
| [query](./kibana-plugin-server.kibanarequest.query.md) | | <code>Query</code> | |
| [route](./kibana-plugin-server.kibanarequest.route.md) | | <code>RecursiveReadonly&lt;KibanaRequestRoute&gt;</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

39 changes: 5 additions & 34 deletions src/core/server/http/http_server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`', () => {
let configWithBasePath: HttpConfig;
let innerServerListener: Server;
Expand Down Expand Up @@ -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 {
registerAuth,
Expand All @@ -768,26 +739,26 @@ describe('#registerAuth', () => {

let fromRegisterOnPreAuth;
await registerOnPreAuth((req, t) => {
fromRegisterOnPreAuth = req.getFilteredHeaders(['authorization']);
fromRegisterOnPreAuth = req.headers.authorization;
return t.next();
});

let fromRegisterAuth;
await registerAuth((req, t) => {
fromRegisterAuth = req.getFilteredHeaders(['authorization']);
fromRegisterAuth = req.headers.authorization;
return t.authenticated();
}, cookieOptions);

let fromRegisterOnPostAuth;
await registerOnPostAuth((req, t) => {
fromRegisterOnPostAuth = req.getFilteredHeaders(['authorization']);
fromRegisterOnPostAuth = req.headers.authorization;
return t.next();
});

let fromRouteHandler;
const router = new Router('');
router.get({ path: '/', validate: false }, (req, res) => {
fromRouteHandler = req.getFilteredHeaders(['authorization']);
fromRouteHandler = req.headers.authorization;
return res.ok({ content: 'ok' });
});
registerRouter(router);
Expand Down
9 changes: 3 additions & 6 deletions src/core/server/http/integration_tests/http_service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ describe('http service', () => {
it('runs auth for legacy routes and proxy request to legacy server route handlers', async () => {
const { http } = await root.setup();
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
const headers = req.getFilteredHeaders(['authorization']);
if (headers.authorization) {
if (req.headers.authorization) {
const user = { id: '42' };
const sessionStorage = sessionStorageFactory.asScoped(req);
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
Expand Down Expand Up @@ -90,8 +89,7 @@ describe('http service', () => {
const token = 'Basic: name:password';
const { http } = await root.setup();
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
const headers = req.getFilteredHeaders(['authorization']);
if (headers.authorization) {
if (req.headers.authorization) {
const user = { id: '42' };
const sessionStorage = sessionStorageFactory.asScoped(req);
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
Expand Down Expand Up @@ -129,8 +127,7 @@ describe('http service', () => {

const { http } = await root.setup();
const { sessionStorageFactory } = await http.registerAuth<StorageData>((req, t) => {
const headers = req.getFilteredHeaders(['authorization']);
if (headers.authorization) {
if (req.headers.authorization) {
const sessionStorage = sessionStorageFactory.asScoped(req);
sessionStorage.set({ value: user, expires: Date.now() + sessionDurationMs });
return t.authenticated({ state: user });
Expand Down
36 changes: 10 additions & 26 deletions src/core/server/http/router/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,41 +30,25 @@ describe('KibanaRequest', () => {
});
});

describe('#getFilteredHeaders', () => {
it('returns request headers', () => {
describe('headers property', () => {
it('provides a frozen copy of request headers', () => {
const rawRequestHeaders = { custom: 'one' };
const request = httpServerMock.createRawRequest({
headers: { custom: 'one' },
headers: rawRequestHeaders,
});
const kibanaRequest = KibanaRequest.from(request);
expect(kibanaRequest.getFilteredHeaders(['custom'])).toEqual({
custom: 'one',
});
});

it('normalizes a header name', () => {
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({});
expect(kibanaRequest.headers).toEqual({ custom: 'one' });
expect(kibanaRequest.headers).not.toBe(rawRequestHeaders);
expect(Object.isFrozen(kibanaRequest.headers)).toBe(true);
});

it("doesn't expose authorization header by default", () => {
it.skip("doesn't expose authorization header by default", () => {
const request = httpServerMock.createRawRequest({
headers: { custom: 'one', authorization: 'token' },
});
const kibanaRequest = KibanaRequest.from(request);
expect(kibanaRequest.getFilteredHeaders(['custom', 'authorization'])).toEqual({
expect(kibanaRequest.headers).toEqual({
custom: 'one',
});
});
Expand All @@ -74,7 +58,7 @@ describe('KibanaRequest', () => {
headers: { custom: 'one', authorization: 'token' },
});
const kibanaRequest = KibanaRequest.from(request, undefined, false);
expect(kibanaRequest.getFilteredHeaders(['custom', 'authorization'])).toEqual({
expect(kibanaRequest.headers).toEqual({
custom: 'one',
authorization: 'token',
});
Expand Down
29 changes: 9 additions & 20 deletions src/core/server/http/router/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
*/

import { Url } from 'url';
import { ObjectType, TypeOf } from '@kbn/config-schema';
import { Request } from 'hapi';

import { ObjectType, TypeOf } from '@kbn/config-schema';

import { deepFreeze, RecursiveReadonly } from '../../../utils';
import { filterHeaders, Headers } from './headers';
import { Headers } from './headers';
import { RouteMethod, RouteSchemas, RouteConfigOptions } from './route';

const requestSymbol = Symbol('request');
Expand All @@ -37,15 +38,8 @@ export interface KibanaRequestRoute {
options: Required<RouteConfigOptions>;
}

const secretHeaders = ['authorization'];
/**
* 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
* */
export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
Expand Down Expand Up @@ -104,8 +98,9 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
public readonly url: Url;
public readonly route: RecursiveReadonly<KibanaRequestRoute>;
/**
* This property will be removed in future version of this class, please
* use the `getFilteredHeaders` method instead
* Readonly copy of incoming request headers.
* @remarks
* This property will contain a `filtered` copy of request headers.
*/
public readonly headers: Headers;

Expand All @@ -117,10 +112,12 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
readonly params: Params,
readonly query: Query,
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
) {
this.url = request.url;
this.headers = request.headers;
this.headers = deepFreeze({ ...request.headers });

// prevent Symbol exposure via Object.getOwnPropertySymbols()
Object.defineProperty(this, requestSymbol, {
Expand All @@ -131,14 +128,6 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
this.route = deepFreeze(this.getRouteInfo());
}

public getFilteredHeaders(headersToKeep: string[]) {
return filterHeaders(
this[requestSymbol].headers,
headersToKeep,
this.withoutSecretHeaders ? secretHeaders : []
);
}

private getRouteInfo() {
const request = this[requestSymbol];
return {
Expand Down
2 changes: 0 additions & 2 deletions src/core/server/server.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ export class KibanaRequest<Params = unknown, Query = unknown, Body = unknown> {
//
// @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"]>;
// (undocumented)
getFilteredHeaders(headersToKeep: string[]): Pick<Record<string, string | string[] | undefined>, string>;
readonly headers: Headers;
// (undocumented)
readonly params: Params;
Expand Down

0 comments on commit 484351b

Please sign in to comment.