diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts index 7b4484cf8a3d..03a6aaad7764 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -58,13 +58,20 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { this.rootComponent = component; }; - public hadValidLicense() { + public hasValidLicense() { if (!this.xpackInfo) { return false; } return this.xpackInfo.get('features.beats_management.licenseValid', false); } + public licenseExpired() { + if (!this.xpackInfo) { + return false; + } + return this.xpackInfo.get('features.beats_management.licenseExpired', false); + } + public securityEnabled() { if (!this.xpackInfo) { return false; @@ -83,8 +90,9 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { public registerManagementSection(pluginId: string, displayName: string, basePath: string) { this.register(this.uiModule); + this.hookAngular(() => { - if (this.hadValidLicense() && this.securityEnabled()) { + if (this.hasValidLicense()) { const registerSection = () => this.management.register(pluginId, { display: 'Beats', // TODO these need to be config options not hard coded in the adapter @@ -92,7 +100,6 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { order: 30, }); const getSection = () => this.management.getSection(pluginId); - const section = this.management.hasItem(pluginId) ? getSection() : registerSection(); section.register(pluginId, { @@ -132,7 +139,13 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { const xpackInfo = Private(this.XPackInfoProvider); this.xpackInfo = xpackInfo; - this.shieldUser = await $injector.get('ShieldUser').getCurrent().$promise; + if (this.securityEnabled()) { + try { + this.shieldUser = await $injector.get('ShieldUser').getCurrent().$promise; + } catch (e) { + // errors when security disabled, even though we check first because angular + } + } done(); }); diff --git a/x-pack/plugins/beats_management/public/lib/lib.ts b/x-pack/plugins/beats_management/public/lib/lib.ts index a223708a3cc4..d47fb449619a 100644 --- a/x-pack/plugins/beats_management/public/lib/lib.ts +++ b/x-pack/plugins/beats_management/public/lib/lib.ts @@ -55,6 +55,9 @@ export interface FrameworkAdapter { scope: string[]; username: string; }; + licenseExpired(): boolean; + securityEnabled(): boolean; + hasValidLicense(): boolean; setUISettings(key: string, value: any): void; render(component: React.ReactElement): void; } diff --git a/x-pack/plugins/beats_management/public/pages/enforce_security.tsx b/x-pack/plugins/beats_management/public/pages/enforce_security.tsx new file mode 100644 index 000000000000..2b29c01663e1 --- /dev/null +++ b/x-pack/plugins/beats_management/public/pages/enforce_security.tsx @@ -0,0 +1,13 @@ +/* + * 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 * as React from 'react'; +import { NoDataLayout } from '../components/layouts/no_data'; + +export const EnforceSecurityPage: React.SFC = () => ( + +

You must enable security in Kibana and Elasticsearch to use Beats central management.

+
+); diff --git a/x-pack/plugins/beats_management/public/pages/invalid_license.tsx b/x-pack/plugins/beats_management/public/pages/invalid_license.tsx new file mode 100644 index 000000000000..c04f5a4acec1 --- /dev/null +++ b/x-pack/plugins/beats_management/public/pages/invalid_license.tsx @@ -0,0 +1,16 @@ +/* + * 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 * as React from 'react'; +import { NoDataLayout } from '../components/layouts/no_data'; + +export const InvalidLicensePage: React.SFC = () => ( + +

+ Your current license is expired. Enrolled Beats will continue to work, but you need a valid + license to access the Beats Management UI. +

+
+); diff --git a/x-pack/plugins/beats_management/public/pages/no_access.tsx b/x-pack/plugins/beats_management/public/pages/no_access.tsx index 3ed704b4a8cf..4e04e2c2fad7 100644 --- a/x-pack/plugins/beats_management/public/pages/no_access.tsx +++ b/x-pack/plugins/beats_management/public/pages/no_access.tsx @@ -7,7 +7,7 @@ import * as React from 'react'; import { NoDataLayout } from '../components/layouts/no_data'; export const NoAccessPage: React.SFC = () => ( - +

You are not authorized to access Beats central management. To use Beats central management, you need the privileges granted by the `beats_admin` role. diff --git a/x-pack/plugins/beats_management/public/router.tsx b/x-pack/plugins/beats_management/public/router.tsx index 7e8017ee012d..f63e340bf79c 100644 --- a/x-pack/plugins/beats_management/public/router.tsx +++ b/x-pack/plugins/beats_management/public/router.tsx @@ -6,11 +6,12 @@ import React from 'react'; import { HashRouter, Redirect, Route, Switch } from 'react-router-dom'; - import { Header } from './components/layouts/header'; import { BreadcrumbConsumer, RouteWithBreadcrumb } from './components/route_with_breadcrumb'; import { FrontendLibs } from './lib/lib'; import { BeatDetailsPage } from './pages/beat'; +import { EnforceSecurityPage } from './pages/enforce_security'; +import { InvalidLicensePage } from './pages/invalid_license'; import { MainPages } from './pages/main'; import { NoAccessPage } from './pages/no_access'; import { TagPage } from './pages/tag'; @@ -37,6 +38,8 @@ export const PageRouter: React.SFC<{ libs: FrontendLibs }> = ({ libs }) => { )} + {libs.framework.licenseExpired() && } />} + {!libs.framework.securityEnabled() && } />} {!libs.framework.getCurrentUser() || (!libs.framework.getCurrentUser().roles.includes('beats_admin') && !libs.framework.getCurrentUser().roles.includes('superuser') && ( diff --git a/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts index 427d82a18a87..0945db7c6b71 100644 --- a/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/beats_management/server/lib/adapters/framework/kibana_framework_adapter.ts @@ -62,9 +62,6 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { } public exposeStaticDir(urlPath: string, dir: string): void { - if (!this.isSecurityEnabled()) { - return; - } this.server.route({ handler: { directory: { @@ -101,7 +98,7 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { if ( wrappedRequest.user.kind === 'authenticated' && - !wrappedRequest.user.roles.includes('superuser') && + (!wrappedRequest.user.roles.includes('superuser') || !wrappedRequest.user.roles) && difference(requiredRoles, wrappedRequest.user.roles).length !== 0 ) { return h.response().code(403); @@ -126,13 +123,6 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { } } - private isSecurityEnabled = () => { - return ( - this.server.plugins.xpack_main.info.isAvailable() && - this.server.plugins.xpack_main.info.feature('security').isEnabled() - ); - }; - // TODO make key a param private validateConfig() { // @ts-ignore @@ -172,6 +162,7 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { return { securityEnabled: true, licenseValid: false, + licenseExpired: false, message: `Your ${licenseType} license does not support Beats central management features. Please upgrade your license.`, }; } @@ -180,7 +171,8 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { if (!isLicenseActive) { return { securityEnabled: true, - licenseValid: false, + licenseValid: true, + licenseExpired: true, message: `You cannot edit, create, or delete your Beats central management configurations because your ${licenseType} license has expired.`, }; } @@ -193,6 +185,8 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { return { securityEnabled: false, licenseValid: true, + licenseExpired: false, + message, }; } @@ -201,6 +195,7 @@ export class KibanaBackendFrameworkAdapter implements BackendFrameworkAdapter { return { securityEnabled: true, licenseValid: true, + licenseExpired: false, }; } }