From f3385eed76391c473bd1c066696f3c5586686c81 Mon Sep 17 00:00:00 2001 From: Mikhail Shustov Date: Thu, 9 Apr 2020 17:08:45 +0200 Subject: [PATCH] add licence checker wrapper --- .../licensing/common/licensing.mock.ts | 1 + x-pack/plugins/licensing/server/index.ts | 4 ++ .../license_checker_route_handler_wrapper.ts | 40 +++++++++++++ ...sing_checker_route_handler_wrapper.test.ts | 59 +++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 x-pack/plugins/licensing/server/license_checker_route_handler_wrapper.ts create mode 100644 x-pack/plugins/licensing/server/licensing_checker_route_handler_wrapper.test.ts diff --git a/x-pack/plugins/licensing/common/licensing.mock.ts b/x-pack/plugins/licensing/common/licensing.mock.ts index bf8b85e3e981b..4a6b27255587a 100644 --- a/x-pack/plugins/licensing/common/licensing.mock.ts +++ b/x-pack/plugins/licensing/common/licensing.mock.ts @@ -53,6 +53,7 @@ const createLicenseMock = () => { }; mock.check.mockReturnValue({ state: 'valid' }); mock.hasAtLeast.mockReturnValue(true); + mock.getFeature.mockReturnValue({ isAvailable: true, isEnabled: true }); return mock; }; export const licenseMock = { diff --git a/x-pack/plugins/licensing/server/index.ts b/x-pack/plugins/licensing/server/index.ts index 0e14ead7c6c57..1f95459513814 100644 --- a/x-pack/plugins/licensing/server/index.ts +++ b/x-pack/plugins/licensing/server/index.ts @@ -12,3 +12,7 @@ export const plugin = (context: PluginInitializerContext) => new LicensingPlugin export * from '../common/types'; export * from './types'; export { config } from './licensing_config'; +export { + CheckLicense, + licenseCheckerRouteHandlerWrapper, +} from './license_checker_route_handler_wrapper'; diff --git a/x-pack/plugins/licensing/server/license_checker_route_handler_wrapper.ts b/x-pack/plugins/licensing/server/license_checker_route_handler_wrapper.ts new file mode 100644 index 0000000000000..7f07a054c41b7 --- /dev/null +++ b/x-pack/plugins/licensing/server/license_checker_route_handler_wrapper.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + RequestHandler, + RequestHandlerContext, + KibanaRequest, + RouteMethod, + KibanaResponseFactory, +} from 'src/core/server'; + +import { ILicense } from '../common/types'; + +export type CheckLicense = ( + license: ILicense +) => { valid: false; message: string } | { valid: true; message: null }; + +export function licenseCheckerRouteHandlerWrapper( + checkLicense: CheckLicense, + handler: RequestHandler +): RequestHandler { + return async ( + context: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) => { + const licenseCheckResult = checkLicense(context.licensing.license); + + if (licenseCheckResult.valid) { + return handler(context, request, response); + } else { + return response.forbidden({ + body: licenseCheckResult.message, + }); + } + }; +} diff --git a/x-pack/plugins/licensing/server/licensing_checker_route_handler_wrapper.test.ts b/x-pack/plugins/licensing/server/licensing_checker_route_handler_wrapper.test.ts new file mode 100644 index 0000000000000..7bd1cb4e2c883 --- /dev/null +++ b/x-pack/plugins/licensing/server/licensing_checker_route_handler_wrapper.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { httpServerMock } from 'src/core/server/mocks'; + +import { + licenseCheckerRouteHandlerWrapper, + CheckLicense, +} from './license_checker_route_handler_wrapper'; + +const context = { + licensing: { + license: {}, + }, +} as any; +const request = httpServerMock.createKibanaRequest(); + +describe('licenseCheckerRouteHandlerWrapper', () => { + it('calls route handler if checkLicense returns "valid": true', async () => { + const checkLicense: CheckLicense = () => ({ valid: true, message: null }); + const routeHandler = jest.fn(); + const wrapper = licenseCheckerRouteHandlerWrapper(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await wrapper(context, request, response); + + expect(routeHandler).toHaveBeenCalledTimes(1); + expect(routeHandler).toHaveBeenCalledWith(context, request, response); + }); + + it('does not call route handler if checkLicense returns "valid": false', async () => { + const checkLicense: CheckLicense = () => ({ valid: false, message: 'reason' }); + const routeHandler = jest.fn(); + const wrapper = licenseCheckerRouteHandlerWrapper(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await wrapper(context, request, response); + + expect(routeHandler).toHaveBeenCalledTimes(0); + expect(response.forbidden).toHaveBeenCalledTimes(1); + expect(response.forbidden).toHaveBeenCalledWith({ body: 'reason' }); + }); + + it('allows an exception to bubble up if handler throws', async () => { + const checkLicense: CheckLicense = () => ({ valid: true, message: null }); + const routeHandler = () => { + throw new Error('reason'); + }; + const wrapper = licenseCheckerRouteHandlerWrapper(checkLicense, routeHandler); + const response = httpServerMock.createResponseFactory(); + + await expect(wrapper(context, request, response)).rejects.toThrowErrorMatchingInlineSnapshot( + `"reason"` + ); + }); +});