Skip to content

Commit

Permalink
[Reporting] Use the deprecations service to advise critical config ch…
Browse files Browse the repository at this point in the history
…anges (#100427)

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
tsullivan and kibanamachine authored May 27, 2021
1 parent f3c846c commit 417c06b
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 16 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/reporting/server/config/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('deprecations', () => {
const { messages } = applyReportingDeprecations({ roles: { enabled: true } });
expect(messages).toMatchInlineSnapshot(`
Array [
"\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users through feature controls in Management > Security > Roles",
"\\"xpack.reporting.roles\\" is deprecated. Granting reporting privilege through a \\"reporting_user\\" role will not be supported starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users using Kibana application privileges **Management > Security > Roles**.",
]
`);
});
Expand Down
4 changes: 2 additions & 2 deletions x-pack/plugins/reporting/server/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export const config: PluginConfigDescriptor<ReportingConfigType> = {
addDeprecation({
message:
`"${fromPath}.roles" is deprecated. Granting reporting privilege through a "reporting_user" role will not be supported ` +
`starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privilege to users ` +
`through feature controls in Management > Security > Roles`,
`starting in 8.0. Please set 'xpack.reporting.roles.enabled' to 'false' and grant reporting privileges to users ` +
`using Kibana application privileges **Management > Security > Roles**.`,
});
}
},
Expand Down
14 changes: 6 additions & 8 deletions x-pack/plugins/reporting/server/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ import { SecurityPluginSetup } from '../../security/server';
import { DEFAULT_SPACE_ID } from '../../spaces/common/constants';
import { SpacesPluginSetup } from '../../spaces/server';
import { TaskManagerSetupContract, TaskManagerStartContract } from '../../task_manager/server';
import { ReportingConfig } from './';
import { ReportingConfig, ReportingSetup } from './';
import { HeadlessChromiumDriverFactory } from './browsers/chromium/driver_factory';
import { ReportingConfigType } from './config';
import { checkLicense, getExportTypesRegistry, LevelLogger } from './lib';
import { screenshotsObservableFactory, ScreenshotsObservableFn } from './lib/screenshots';
import { ReportingStore } from './lib/store';
import { ExecuteReportTask, MonitorReportsTask, ReportTaskParams } from './lib/tasks';
import { ReportingPluginRouter, ReportingStart } from './types';
import { ReportingPluginRouter } from './types';

export interface ReportingInternalSetup {
basePath: Pick<BasePath, 'set'>;
Expand Down Expand Up @@ -69,19 +69,17 @@ export class ReportingCore {
private config?: ReportingConfig; // final config, includes dynamic values based on OS type
private executing: Set<string>;

public getStartContract: () => ReportingStart;
public getContract: () => ReportingSetup;

constructor(private logger: LevelLogger, context: PluginInitializerContext<ReportingConfigType>) {
const syncConfig = context.config.get<ReportingConfigType>();
this.deprecatedAllowedRoles = syncConfig.roles.enabled ? syncConfig.roles.allow : false;
this.executeTask = new ExecuteReportTask(this, syncConfig, this.logger);
this.monitorTask = new MonitorReportsTask(this, syncConfig, this.logger);

this.getStartContract = (): ReportingStart => {
return {
usesUiCapabilities: () => syncConfig.roles.enabled === false,
};
};
this.getContract = () => ({
usesUiCapabilities: () => syncConfig.roles.enabled === false,
});

this.executing = new Set();
}
Expand Down
107 changes: 107 additions & 0 deletions x-pack/plugins/reporting/server/deprecations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ReportingCore } from '.';
import { registerDeprecations } from './deprecations';
import { createMockConfigSchema, createMockReportingCore } from './test_helpers';
import { coreMock, elasticsearchServiceMock } from 'src/core/server/mocks';
import { GetDeprecationsContext, IScopedClusterClient } from 'kibana/server';

let reportingCore: ReportingCore;
let context: GetDeprecationsContext;
let esClient: jest.Mocked<IScopedClusterClient>;

beforeEach(async () => {
const mockReportingConfig = createMockConfigSchema({ roles: { enabled: false } });
reportingCore = await createMockReportingCore(mockReportingConfig);
esClient = elasticsearchServiceMock.createScopedClusterClient();
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
body: { xyz: { username: 'normal_user', roles: ['data_analyst'] } },
});
context = ({ esClient } as unknown) as GetDeprecationsContext;
});

test('logs no deprecations when setup has no issues', async () => {
const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
expect(await getDeprecations(context)).toMatchInlineSnapshot(`Array []`);
});

test('logs a plain message when only a reporting_user role issue is found', async () => {
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } },
});

const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
Array [
Object {
"correctiveActions": Object {
"manualSteps": Array [
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
],
},
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
"level": "critical",
"message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"",
},
]
`);
});

test('logs multiple entries when multiple reporting_user role issues are found', async () => {
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
body: {
reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] },
supercooluser: { username: 'supercooluser', roles: ['kibana_admin', 'reporting_user'] },
},
});

const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
Array [
Object {
"correctiveActions": Object {
"manualSteps": Array [
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
],
},
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
"level": "critical",
"message": "The deprecated \\"reporting_user\\" role has been found for 2 user(s): \\"reportron\\", \\"supercooluser\\"",
},
]
`);
});

test('logs an expanded message when a config issue and a reporting_user role issue is found', async () => {
esClient.asCurrentUser.security.getUser = jest.fn().mockResolvedValue({
body: { reportron: { username: 'reportron', roles: ['kibana_admin', 'reporting_user'] } },
});

const mockReportingConfig = createMockConfigSchema({ roles: { enabled: true } });
reportingCore = await createMockReportingCore(mockReportingConfig);

const { getDeprecations } = await registerDeprecations(reportingCore, coreMock.createSetup());
expect(await getDeprecations(context)).toMatchInlineSnapshot(`
Array [
Object {
"correctiveActions": Object {
"manualSteps": Array [
"Set \\"xpack.reporting.roles.enabled: false\\" in kibana.yml",
"Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.",
"Assign the custom role(s) as desired, and remove the \\"reporting_user\\" role from the user(s).",
],
},
"documentationUrl": "https://www.elastic.co/guide/en/kibana/current/secure-reporting.html",
"level": "critical",
"message": "The deprecated \\"reporting_user\\" role has been found for 1 user(s): \\"reportron\\"",
},
]
`);
});
52 changes: 52 additions & 0 deletions x-pack/plugins/reporting/server/deprecations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { CoreSetup, DeprecationsDetails, RegisterDeprecationsConfig } from 'src/core/server';
import { ReportingCore } from '.';

const deprecatedRole = 'reporting_user';
const upgradableConfig = 'xpack.reporting.roles.enabled: false';

export async function registerDeprecations(
reporting: ReportingCore,
{ deprecations: deprecationsService }: CoreSetup
) {
const deprecationsConfig: RegisterDeprecationsConfig = {
getDeprecations: async ({ esClient }) => {
const usingDeprecatedConfig = !reporting.getContract().usesUiCapabilities();
const deprecations: DeprecationsDetails[] = [];
const { body: users } = await esClient.asCurrentUser.security.getUser();

const reportingUsers = Object.entries(users)
.filter(([username, user]) => user.roles.includes(deprecatedRole))
.map(([, user]) => user.username);
const numReportingUsers = reportingUsers.length;

if (numReportingUsers > 0) {
const usernames = reportingUsers.join('", "');
deprecations.push({
message: `The deprecated "${deprecatedRole}" role has been found for ${numReportingUsers} user(s): "${usernames}"`,
documentationUrl: 'https://www.elastic.co/guide/en/kibana/current/secure-reporting.html',
level: 'critical',
correctiveActions: {
manualSteps: [
...(usingDeprecatedConfig ? [`Set "${upgradableConfig}" in kibana.yml`] : []),
`Create one or more custom roles that provide Kibana application privileges to reporting features in **Management > Security > Roles**.`,
`Assign the custom role(s) as desired, and remove the "${deprecatedRole}" role from the user(s).`,
],
},
});
}

return deprecations;
},
};

deprecationsService.registerDeprecations(deprecationsConfig);

return deprecationsConfig;
}
11 changes: 6 additions & 5 deletions x-pack/plugins/reporting/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { PLUGIN_ID } from '../common/constants';
import { ReportingCore } from './';
import { initializeBrowserDriverFactory } from './browsers';
import { buildConfig, registerUiSettings, ReportingConfigType } from './config';
import { registerDeprecations } from './deprecations';
import { LevelLogger, ReportingStore } from './lib';
import { registerRoutes } from './routes';
import { setFieldFormats } from './services';
Expand Down Expand Up @@ -38,15 +39,13 @@ export class ReportingPlugin
// @ts-expect-error null is not assignable to object. use a boolean property to ensure reporting API is enabled.
core.http.registerRouteHandlerContext(PLUGIN_ID, () => {
if (reportingCore.pluginIsStarted()) {
return reportingCore.getStartContract();
return reportingCore.getContract();
} else {
this.logger.error(`Reporting features are not yet ready`);
return null;
}
});

registerUiSettings(core);

const { http } = core;
const { screenshotMode, features, licensing, security, spaces, taskManager } = plugins;

Expand All @@ -65,6 +64,8 @@ export class ReportingPlugin
logger: this.logger,
});

registerUiSettings(core);
registerDeprecations(reportingCore, core);
registerReportingUsageCollector(reportingCore, plugins);
registerRoutes(reportingCore, this.logger);

Expand All @@ -81,7 +82,7 @@ export class ReportingPlugin
});

this.reportingCore = reportingCore;
return reportingCore.getStartContract();
return reportingCore.getContract();
}

public start(core: CoreStart, plugins: ReportingStartDeps) {
Expand Down Expand Up @@ -116,6 +117,6 @@ export class ReportingPlugin
this.logger.error(e);
});

return reportingCore.getStartContract();
return reportingCore.getContract();
}
}

0 comments on commit 417c06b

Please sign in to comment.