Skip to content

Commit

Permalink
Merge branch 'master' into task-manager/schema-config
Browse files Browse the repository at this point in the history
* master:
  allows Alerts to recover gracefully from Executor errors (elastic#53688)
  [Console] Fix OSS build (elastic#53885)
  migrate xsrf / version-check / custom-headers handlers to NP (elastic#53684)
  use NP deprecations in uiSettings (elastic#53755)
  adds strict types to Alerting Client (elastic#53821)
  [Dashboard] Empty screen redesign (elastic#53681)
  Migrate config deprecations and `ShieldUser` functionality to the New Platform (elastic#53768)
  • Loading branch information
gmmorris committed Jan 6, 2020
2 parents 2047538 + 785b916 commit a330d9a
Show file tree
Hide file tree
Showing 113 changed files with 2,591 additions and 1,623 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@
"fast-deep-equal": "^3.1.1",
"file-loader": "4.2.0",
"font-awesome": "4.7.0",
"fp-ts": "^2.3.1",
"getos": "^3.1.0",
"glob": "^7.1.2",
"glob-all": "^3.1.0",
Expand All @@ -188,6 +189,7 @@
"hoek": "^5.0.4",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.2",
"immer": "^1.5.0",
"inert": "^5.1.0",
"inline-style": "^2.0.0",
"joi": "^13.5.2",
Expand Down
1 change: 0 additions & 1 deletion src/core/server/config/deprecation/core_deprecations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export const coreDeprecationProvider: ConfigDeprecationProvider = ({
}) => [
unusedFromRoot('savedObjects.indexCheckTimeout'),
unusedFromRoot('server.xsrf.token'),
unusedFromRoot('uiSettings.enabled'),
renameFromRoot('optimize.lazy', 'optimize.watch'),
renameFromRoot('optimize.lazyPort', 'optimize.watchPort'),
renameFromRoot('optimize.lazyHost', 'optimize.watchHost'),
Expand Down
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.

4 changes: 4 additions & 0 deletions src/core/server/http/cookie_session_storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ configService.atPath.mockReturnValue(
verificationMode: 'none',
},
compression: { enabled: true },
xsrf: {
disableProtection: true,
whitelist: [],
},
} as any)
);

Expand Down
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 @@ -23,6 +23,11 @@ import { config, HttpConfig } from '.';
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 @@ -84,6 +89,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
30 changes: 19 additions & 11 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 { CspConfigType, CspConfig, ICspConfig } from '../csp';
import { SslConfig, sslSchema } from './ssl_config';

Expand All @@ -33,21 +35,13 @@ export const config = {
path: 'server',
schema: schema.object(
{
name: schema.string({ defaultValue: () => hostname() }),
autoListen: schema.boolean({ defaultValue: true }),
basePath: schema.maybe(
schema.string({
validate: match(validBasePathRegex, "must start with a slash, don't end with one"),
})
),
defaultRoute: schema.maybe(
schema.string({
validate(value) {
if (!value.startsWith('/')) {
return 'must start with a slash';
}
},
})
),
cors: schema.conditional(
schema.contextRef('dev'),
true,
Expand All @@ -63,6 +57,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 @@ -97,6 +94,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 @@ -125,19 +129,21 @@ 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;
public defaultRoute?: string;
public ssl: SslConfig;
public compression: { enabled: boolean; referrerWhitelist?: string[] };
public csp: ICspConfig;
public xsrf: { disableProtection: boolean; whitelist: string[] };

/**
* @internal
Expand All @@ -147,14 +153,16 @@ export class HttpConfig {
this.host = rawHttpConfig.host;
this.port = rawHttpConfig.port;
this.cors = rawHttpConfig.cors;
this.customResponseHeaders = rawHttpConfig.customResponseHeaders;
this.maxPayload = rawHttpConfig.maxPayload;
this.name = rawHttpConfig.name;
this.basePath = rawHttpConfig.basePath;
this.keepaliveTimeout = rawHttpConfig.keepaliveTimeout;
this.socketTimeout = rawHttpConfig.socketTimeout;
this.rewriteBasePath = rawHttpConfig.rewriteBasePath;
this.ssl = new SslConfig(rawHttpConfig.ssl || {});
this.defaultRoute = rawHttpConfig.defaultRoute;
this.compression = rawHttpConfig.compression;
this.csp = new CspConfig(rawCspConfig);
this.xsrf = rawHttpConfig.xsrf;
}
}
13 changes: 13 additions & 0 deletions src/core/server/http/http_server.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ import {
RouteMethod,
KibanaResponseFactory,
} from './router';
import { OnPreResponseToolkit } from './lifecycle/on_pre_response';
import { OnPostAuthToolkit } from './lifecycle/on_post_auth';
import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';

interface RequestFixtureOptions {
headers?: Record<string, string>;
Expand Down Expand Up @@ -137,9 +140,19 @@ const createLifecycleResponseFactoryMock = (): jest.Mocked<LifecycleResponseFact
customError: jest.fn(),
});

type ToolkitMock = jest.Mocked<OnPreResponseToolkit & OnPostAuthToolkit & OnPreAuthToolkit>;

const createToolkitMock = (): ToolkitMock => {
return {
next: jest.fn(),
rewriteUrl: jest.fn(),
};
};

export const httpServerMock = {
createKibanaRequest: createKibanaRequestMock,
createRawRequest: createRawRequestMock,
createResponseFactory: createResponseFactoryMock,
createLifecycleResponseFactory: createLifecycleResponseFactoryMock,
createToolkit: createToolkitMock,
};
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
1 change: 0 additions & 1 deletion src/core/server/http/http_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ const createSetupContractMock = () => {
getAuthHeaders: jest.fn(),
},
isTlsEnabled: false,
config: {},
};
setupContract.createCookieSessionStorageFactory.mockResolvedValue(
sessionStorageMock.createFactory()
Expand Down
4 changes: 4 additions & 0 deletions src/core/server/http/http_service.test.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,7 @@ jest.mock('./http_server', () => {
HttpServer: mockHttpServer,
};
});

jest.mock('./lifecycle_handlers', () => ({
registerCoreHandlers: jest.fn(),
}));
23 changes: 12 additions & 11 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 } = 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)));
configService.atPath<CspConfigType>(cspConfig.path),
]).pipe(map(([http, csp]) => new HttpConfig(http, csp)));
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 All @@ -107,10 +112,6 @@ export class HttpService implements CoreService<InternalHttpServiceSetup, HttpSe
contextName: T,
provider: RequestHandlerContextProvider<T>
) => this.requestHandlerContext!.registerContext(pluginOpaqueId, contextName, provider),

config: {
defaultRoute: config.defaultRoute,
},
};

return contract;
Expand Down
Loading

0 comments on commit a330d9a

Please sign in to comment.