From 37aa62076513d83f7d4f0f0c4abf7bc72ca0acaf Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Wed, 8 Jan 2025 08:20:08 -0700 Subject: [PATCH] [Reporting] Functional tests for privileges with built-in reporting_user (#205827) Closes https://github.com/elastic/kibana-team/issues/1389 https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/7665 --- .../default_reporting_user_role.ts | 48 +++++++++++++++++++ .../reporting_and_security/index.ts | 1 + .../services/scenarios.ts | 11 +++-- .../services/usage.ts | 26 ++++++---- 4 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 x-pack/test/reporting_api_integration/reporting_and_security/default_reporting_user_role.ts diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/default_reporting_user_role.ts b/x-pack/test/reporting_api_integration/reporting_and_security/default_reporting_user_role.ts new file mode 100644 index 0000000000000..b559463eee6e5 --- /dev/null +++ b/x-pack/test/reporting_api_integration/reporting_and_security/default_reporting_user_role.ts @@ -0,0 +1,48 @@ +/* + * 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 { FtrProviderContext } from '../ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function ({ getService }: FtrProviderContext) { + const reportingAPI = getService('reportingAPI'); + const security = getService('security'); + const log = getService('log'); + + const testUserUsername = 'test_reporting_user'; + const testUserPassword = 'changeme'; + + describe('Default reporting_user role', () => { + before(async () => { + await reportingAPI.initEcommerce(); + + log.info('creating test user with reporting_user role'); + await security.user.create(testUserUsername, { + password: testUserPassword, + roles: ['data_analyst', 'reporting_user'], // no custom privileges to reporting, uses the built-in role that grants access to all features in all applications and all spaces + full_name: + 'a reporting user which uses the built-in reporting_user role to access reporting features', + }); + }); + + after(async () => { + await reportingAPI.teardownEcommerce(); + }); + + it('able to generate CSV report', async () => { + log.info('posting test report job with test user account'); + const reportPath = await reportingAPI.postJob( + '/api/reporting/generate/csv_searchsource?jobParams=%28browserTimezone%3AAmerica%2FPhoenix%2Ccolumns%3A%21%28order_date%2Ccategory%2Ccurrency%2Ccustomer_id%2Corder_id%2Cday_of_week_i%2Cproducts.created_on%2Csku%29%2CobjectType%3Asearch%2CsearchSource%3A%28fields%3A%21%28%28field%3Aorder_date%2Cinclude_unmapped%3A%21t%29%2C%28field%3Acategory%2Cinclude_unmapped%3A%21t%29%2C%28field%3Acurrency%2Cinclude_unmapped%3A%21t%29%2C%28field%3Acustomer_id%2Cinclude_unmapped%3A%21t%29%2C%28field%3Aorder_id%2Cinclude_unmapped%3A%21t%29%2C%28field%3Aday_of_week_i%2Cinclude_unmapped%3A%21t%29%2C%28field%3Aproducts.created_on%2Cinclude_unmapped%3A%21t%29%2C%28field%3Asku%2Cinclude_unmapped%3A%21t%29%29%2Cfilter%3A%21%28%28meta%3A%28field%3Aorder_date%2Cindex%3A%275193f870-d861-11e9-a311-0fa548c5f953%27%2Cparams%3A%28%29%29%2Cquery%3A%28range%3A%28order_date%3A%28format%3Astrict_date_optional_time%2Cgte%3A%272019-07-01T20%3A56%3A00.833Z%27%2Clte%3A%272019-07-02T15%3A09%3A46.563Z%27%29%29%29%29%29%2Cindex%3A%275193f870-d861-11e9-a311-0fa548c5f953%27%2Cquery%3A%28language%3Akuery%2Cquery%3A%27%27%29%2Csort%3A%21%28%28order_date%3A%28format%3Astrict_date_optional_time%2Corder%3Adesc%29%29%2C%28order_id%3Adesc%29%29%2Cversion%3A%21t%29%2Ctitle%3A%27Ecommerce%20Data%27%2Cversion%3A%279.0.0%27%29', + testUserUsername, + testUserPassword + ); + log.info('test report job download path: ', reportPath); + + await reportingAPI.waitForJobToFinish(reportPath, false, testUserUsername, testUserPassword); + }); + }); +} diff --git a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts index 8bd69780b44b7..6caffc5d562e1 100644 --- a/x-pack/test/reporting_api_integration/reporting_and_security/index.ts +++ b/x-pack/test/reporting_api_integration/reporting_and_security/index.ts @@ -21,6 +21,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./bwc_existing_indexes')); loadTestFile(require.resolve('./datastream')); + loadTestFile(require.resolve('./default_reporting_user_role')); loadTestFile(require.resolve('./ilm_migration_apis')); loadTestFile(require.resolve('./security_roles_privileges')); loadTestFile(require.resolve('./spaces')); diff --git a/x-pack/test/reporting_api_integration/services/scenarios.ts b/x-pack/test/reporting_api_integration/services/scenarios.ts index ed542cc74e44e..0800647d2abef 100644 --- a/x-pack/test/reporting_api_integration/services/scenarios.ts +++ b/x-pack/test/reporting_api_integration/services/scenarios.ts @@ -25,9 +25,9 @@ export function createScenarios({ getService }: Pick => { + const postJob = async ( + apiPath: string, + username = 'elastic', + password = process.env.TEST_KIBANA_PASS || 'changeme' + ): Promise => { log.debug(`ReportingAPI.postJob(${apiPath})`); - const { body } = await supertest + const { body } = await supertestWithoutAuth .post(removeWhitespace(apiPath)) + .auth(username, password) .set('kbn-xsrf', 'xxx') .expect(200); return body.path; diff --git a/x-pack/test/reporting_api_integration/services/usage.ts b/x-pack/test/reporting_api_integration/services/usage.ts index 3e9167e44e522..52ec94e7e7f53 100644 --- a/x-pack/test/reporting_api_integration/services/usage.ts +++ b/x-pack/test/reporting_api_integration/services/usage.ts @@ -13,17 +13,25 @@ import { FtrProviderContext } from '../ftr_provider_context'; export function createUsageServices({ getService }: FtrProviderContext) { const log = getService('log'); const esSupertest = getService('esSupertest'); - const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); return { - async waitForJobToFinish(downloadReportPath: string, ignoreFailure = false) { + async waitForJobToFinish( + downloadReportPath: string, + ignoreFailure = false, + username = 'elastic', + password = process.env.TEST_KIBANA_PASS || 'changeme' + ) { log.debug(`Waiting for job to finish: ${downloadReportPath}`); const JOB_IS_PENDING_CODE = 503; let response: Response & { statusCode?: number }; const statusCode = await new Promise((resolve) => { const intervalId = setInterval(async () => { - response = await supertest.get(downloadReportPath).responseType('blob'); + response = await supertestWithoutAuth + .get(downloadReportPath) + .auth(username, password) + .responseType('blob'); if (response.statusCode === 503) { log.debug(`Report at path ${downloadReportPath} is pending`); } else if (response.statusCode === 200) { @@ -38,12 +46,14 @@ export function createUsageServices({ getService }: FtrProviderContext) { }, 1500); }); if (!ignoreFailure) { - const jobInfo = await supertest.get( - downloadReportPath.replace( - PUBLIC_ROUTES.JOBS.DOWNLOAD_PREFIX, - INTERNAL_ROUTES.JOBS.INFO_PREFIX + const jobInfo = await supertestWithoutAuth + .get( + downloadReportPath.replace( + PUBLIC_ROUTES.JOBS.DOWNLOAD_PREFIX, + INTERNAL_ROUTES.JOBS.INFO_PREFIX + ) ) - ); + .auth(username, password); expect(jobInfo.body.output.warnings).to.be(undefined); // expect no failure message to be present in job info expect(statusCode).to.be(200); }