Skip to content

Commit

Permalink
migrate xsrf / version-check / custom-headers handlers to NP
Browse files Browse the repository at this point in the history
  • Loading branch information
pgayvallet committed Dec 20, 2019
1 parent 672eac0 commit 159e542
Show file tree
Hide file tree
Showing 19 changed files with 718 additions and 346 deletions.
6 changes: 6 additions & 0 deletions src/core/server/http/__snapshots__/http_config.test.ts.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/core/server/http/http_config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import { getEnvOptions } from '../config/__mocks__/env';
const validHostnames = ['www.example.com', '8.8.8.8', '::1', 'localhost'];
const invalidHostname = 'asdf$%^';

jest.mock('os', () => ({
...jest.requireActual('os'),
hostname: () => 'kibana-hostname',
}));

test('has defaults for config', () => {
const httpSchema = config.schema;
const obj = {};
Expand Down Expand Up @@ -86,6 +91,24 @@ test('accepts only valid uuids for server.uuid', () => {
);
});

test('uses os.hostname() as default for server.name', () => {
const httpSchema = config.schema;
const validated = httpSchema.validate({});
expect(validated.name).toEqual('kibana-hostname');
});

test('throws if xsrf.whitelist element does not start with a slash', () => {
const httpSchema = config.schema;
const obj = {
xsrf: {
whitelist: ['/valid-path', 'invalid-path'],
},
};
expect(() => httpSchema.validate(obj)).toThrowErrorMatchingInlineSnapshot(
`"[xsrf.whitelist.1]: must start with a slash"`
);
});

describe('with TLS', () => {
test('throws if TLS is enabled but `key` is not specified', () => {
const httpSchema = config.schema;
Expand Down
19 changes: 19 additions & 0 deletions src/core/server/http/http_config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/

import { ByteSizeValue, schema, TypeOf } from '@kbn/config-schema';
import { hostname } from 'os';

import { Env } from '../config';
import { CspConfigType, CspConfig, ICspConfig } from '../csp';
import { SslConfig, sslSchema } from './ssl_config';
Expand All @@ -34,6 +36,7 @@ export const config = {
path: 'server',
schema: schema.object(
{
name: schema.string({ defaultValue: () => hostname() }),
autoListen: schema.boolean({ defaultValue: true }),
basePath: schema.maybe(
schema.string({
Expand Down Expand Up @@ -64,6 +67,9 @@ export const config = {
),
schema.boolean({ defaultValue: false })
),
customResponseHeaders: schema.recordOf(schema.string(), schema.string(), {
defaultValue: {},
}),
host: schema.string({
defaultValue: 'localhost',
hostname: true,
Expand Down Expand Up @@ -98,6 +104,13 @@ export const config = {
validate: match(uuidRegexp, 'must be a valid uuid'),
})
),
xsrf: schema.object({
disableProtection: schema.boolean({ defaultValue: false }),
whitelist: schema.arrayOf(
schema.string({ validate: match(/^\//, 'must start with a slash') }),
{ defaultValue: [] }
),
}),
},
{
validate: rawConfig => {
Expand Down Expand Up @@ -126,12 +139,14 @@ export const config = {
export type HttpConfigType = TypeOf<typeof config.schema>;

export class HttpConfig {
public name: string;
public autoListen: boolean;
public host: string;
public keepaliveTimeout: number;
public socketTimeout: number;
public port: number;
public cors: boolean | { origin: string[] };
public customResponseHeaders: Record<string, string>;
public maxPayload: ByteSizeValue;
public basePath?: string;
public rewriteBasePath: boolean;
Expand All @@ -140,15 +155,18 @@ export class HttpConfig {
public ssl: SslConfig;
public compression: { enabled: boolean; referrerWhitelist?: string[] };
public csp: ICspConfig;
public xsrf: { disableProtection: boolean; whitelist: string[] };

/**
* @internal
*/
constructor(rawHttpConfig: HttpConfigType, rawCspConfig: CspConfigType, env: Env) {
this.name = rawHttpConfig.name;
this.autoListen = rawHttpConfig.autoListen;
this.host = rawHttpConfig.host;
this.port = rawHttpConfig.port;
this.cors = rawHttpConfig.cors;
this.customResponseHeaders = rawHttpConfig.customResponseHeaders;
this.maxPayload = rawHttpConfig.maxPayload;
this.basePath = rawHttpConfig.basePath;
this.keepaliveTimeout = rawHttpConfig.keepaliveTimeout;
Expand All @@ -159,5 +177,6 @@ export class HttpConfig {
this.defaultRoute = rawHttpConfig.defaultRoute;
this.compression = rawHttpConfig.compression;
this.csp = new CspConfig(rawCspConfig);
this.xsrf = rawHttpConfig.xsrf;
}
}
6 changes: 6 additions & 0 deletions src/core/server/http/http_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export interface HttpServerSetup {
};
}

/** @internal */
export type LifecycleRegistrar = Pick<
HttpServerSetup,
'registerAuth' | 'registerOnPreAuth' | 'registerOnPostAuth' | 'registerOnPreResponse'
>;

export class HttpServer {
private server?: Server;
private config?: HttpConfig;
Expand Down
17 changes: 11 additions & 6 deletions src/core/server/http/http_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import { Observable, Subscription, combineLatest } from 'rxjs';
import { first, map } from 'rxjs/operators';
import { Server } from 'hapi';

import { LoggerFactory } from '../logging';
import { CoreService } from '../../types';

import { Logger } from '../logging';
import { Logger, LoggerFactory } from '../logging';
import { ContextSetup } from '../context';
import { Env } from '../config';
import { CoreContext } from '../core_context';
import { PluginOpaqueId } from '../plugins';
import { CspConfigType, config as cspConfig } from '../csp';
Expand All @@ -43,6 +42,7 @@ import {
} from './types';

import { RequestHandlerContext } from '../../server';
import { registerCoreHandlers } from './lifecycle_handlers';

interface SetupDeps {
context: ContextSetup;
Expand All @@ -57,18 +57,20 @@ export class HttpService implements CoreService<InternalHttpServiceSetup, HttpSe

private readonly logger: LoggerFactory;
private readonly log: Logger;
private readonly env: Env;
private notReadyServer?: Server;
private requestHandlerContext?: RequestHandlerContextContainer;

constructor(private readonly coreContext: CoreContext) {
const { logger, configService, env } = coreContext;

this.logger = logger;
this.env = env;
this.log = logger.get('http');
this.config$ = combineLatest(
this.config$ = combineLatest([
configService.atPath<HttpConfigType>(httpConfig.path),
configService.atPath<CspConfigType>(cspConfig.path)
).pipe(map(([http, csp]) => new HttpConfig(http, csp, env)));
configService.atPath<CspConfigType>(cspConfig.path),
]).pipe(map(([http, csp]) => new HttpConfig(http, csp, env)));
this.httpServer = new HttpServer(logger, 'Kibana');
this.httpsRedirectServer = new HttpsRedirectServer(logger.get('http', 'redirect', 'server'));
}
Expand All @@ -92,6 +94,9 @@ export class HttpService implements CoreService<InternalHttpServiceSetup, HttpSe
}

const { registerRouter, ...serverContract } = await this.httpServer.setup(config);

registerCoreHandlers(serverContract, config, this.env);

const contract: InternalHttpServiceSetup = {
...serverContract,

Expand Down
Loading

0 comments on commit 159e542

Please sign in to comment.