Skip to content

Commit

Permalink
Add test service to manage observability test users (#110849) (#111286)
Browse files Browse the repository at this point in the history
Co-authored-by: Kibana Machine <[email protected]>

Co-authored-by: Felix Stürmer <[email protected]>
  • Loading branch information
kibanamachine and weltenwort authored Sep 6, 2021
1 parent f3421a0 commit dd6c75d
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context';

export default function ({ getPageObjects, getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const security = getService('security');
const observability = getService('observability');
const PageObjects = getPageObjects([
'common',
'observability',
Expand All @@ -20,6 +20,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
]);
const appsMenu = getService('appsMenu');
const testSubjects = getService('testSubjects');

describe('observability security feature controls', function () {
this.tags(['skipFirefox']);
before(async () => {
Expand All @@ -32,39 +33,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {

describe('observability cases all privileges', () => {
before(async () => {
await security.role.create('cases_observability_all_role', {
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{ spaces: ['*'], base: [], feature: { observabilityCases: ['all'], logs: ['all'] } },
],
});

await security.user.create('cases_observability_all_user', {
password: 'cases_observability_all_user-password',
roles: ['cases_observability_all_role'],
full_name: 'test user',
});

await PageObjects.security.forceLogout();

await PageObjects.security.login(
'cases_observability_all_user',
'cases_observability_all_user-password',
{
expectSpaceSelector: false,
}
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
observabilityCases: ['all'],
logs: ['all'],
})
);
});

after(async () => {
await PageObjects.security.forceLogout();
await Promise.all([
security.role.delete('cases_observability_all_role'),
security.user.delete('cases_observability_all_user'),
]);
await observability.users.restoreDefaultTestUserRole();
});

it('shows observability/cases navlink', async () => {
await PageObjects.common.navigateToActualUrl('observability');
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).to.contain('Cases');
});
Expand Down Expand Up @@ -101,38 +83,20 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {

describe('observability cases read-only privileges', () => {
before(async () => {
await security.role.create('cases_observability_read_role', {
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{
spaces: ['*'],
base: [],
feature: { observabilityCases: ['read'], logs: ['all'] },
},
],
});

await security.user.create('cases_observability_read_user', {
password: 'cases_observability_read_user-password',
roles: ['cases_observability_read_role'],
full_name: 'test user',
});

await PageObjects.security.login(
'cases_observability_read_user',
'cases_observability_read_user-password',
{
expectSpaceSelector: false,
}
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
observabilityCases: ['read'],
logs: ['all'],
})
);
});

after(async () => {
await security.role.delete('cases_observability_read_role');
await security.user.delete('cases_observability_read_user');
await observability.users.restoreDefaultTestUserRole();
});

it('shows observability/cases navlink', async () => {
await PageObjects.common.navigateToActualUrl('observability');
const navLinks = (await appsMenu.readLinks()).map((link) => link.text);
expect(navLinks).to.contain('Cases');
});
Expand Down Expand Up @@ -170,36 +134,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {

describe('no observability privileges', () => {
before(async () => {
await security.role.create('no_observability_privileges_role', {
await observability.users.setTestUserRole({
elasticsearch: { cluster: [], indices: [], run_as: [] },
kibana: [
{
feature: {
discover: ['all'],
},
spaces: ['*'],
},
],
kibana: [{ spaces: ['*'], base: [], feature: { discover: ['all'] } }],
});

await security.user.create('no_observability_privileges_user', {
password: 'no_observability_privileges_user-password',
roles: ['no_observability_privileges_role'],
full_name: 'test user',
});

await PageObjects.security.login(
'no_observability_privileges_user',
'no_observability_privileges_user-password',
{
expectSpaceSelector: false,
}
);
});

after(async () => {
await security.role.delete('no_observability_privileges_role');
await security.user.delete('no_observability_privileges_user');
await observability.users.restoreDefaultTestUserRole();
});

it(`returns a 403`, async () => {
Expand Down
2 changes: 2 additions & 0 deletions x-pack/test/functional/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
DashboardPanelTimeRangeProvider,
} from './dashboard';
import { SearchSessionsService } from './search_sessions';
import { ObservabilityProvider } from './observability';

// define the name and providers for services that should be
// available to your tests. If you don't specify anything here
Expand Down Expand Up @@ -110,4 +111,5 @@ export const services = {
dashboardPanelTimeRange: DashboardPanelTimeRangeProvider,
reporting: ReportingFunctionalProvider,
searchSessions: SearchSessionsService,
observability: ObservabilityProvider,
};
17 changes: 17 additions & 0 deletions x-pack/test/functional/services/observability/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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';
import { ObservabilityUsersProvider } from './users';

export function ObservabilityProvider(context: FtrProviderContext) {
const users = ObservabilityUsersProvider(context);

return {
users,
};
}
92 changes: 92 additions & 0 deletions x-pack/test/functional/services/observability/users.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* 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 { Role } from '../../../../plugins/security/common/model';
import { FtrProviderContext } from '../../ftr_provider_context';

type CreateRolePayload = Pick<Role, 'metadata' | 'elasticsearch' | 'kibana'>;

const OBSERVABILITY_TEST_ROLE_NAME = 'observability-functional-test-role';

export function ObservabilityUsersProvider({ getPageObject, getService }: FtrProviderContext) {
const security = getService('security');
const commonPageObject = getPageObject('common');

/**
* Creates a test role and set it as the test user's role. Performs a page
* reload to apply the role change, but doesn't require a re-login.
*
* @arg roleDefinition - the privileges of the test role
*/
const setTestUserRole = async (roleDefinition: CreateRolePayload) => {
// return to neutral grounds to avoid running into permission problems on reload
await commonPageObject.navigateToActualUrl('kibana');

await security.role.create(OBSERVABILITY_TEST_ROLE_NAME, roleDefinition);

await security.testUser.setRoles([OBSERVABILITY_TEST_ROLE_NAME]); // performs a page reload
};

/**
* Deletes the test role and restores thedefault test user role. Performs a
* page reload to apply the role change, but doesn't require a re-login.
*/
const restoreDefaultTestUserRole = async () => {
await Promise.all([
security.role.delete(OBSERVABILITY_TEST_ROLE_NAME),
security.testUser.restoreDefaults(),
]);
};

return {
defineBasicObservabilityRole,
restoreDefaultTestUserRole,
setTestUserRole,
};
}

/**
* Generates a combination of Elasticsearch and Kibana privileges for given
* observability features.
*/
const defineBasicObservabilityRole = (
features: Partial<{
observabilityCases: string[];
apm: string[];
logs: string[];
infrastructure: string[];
uptime: string[];
}>
): CreateRolePayload => {
return {
elasticsearch: {
cluster: ['all'],
indices: [
...((features.logs?.length ?? 0) > 0
? [{ names: ['filebeat-*', 'logs-*'], privileges: ['all'] }]
: []),
...((features.infrastructure?.length ?? 0) > 0
? [{ names: ['metricbeat-*', 'metrics-*'], privileges: ['all'] }]
: []),
...((features.apm?.length ?? 0) > 0 ? [{ names: ['apm-*'], privileges: ['all'] }] : []),
...((features.uptime?.length ?? 0) > 0
? [{ names: ['heartbeat-*,synthetics-*'], privileges: ['all'] }]
: []),
],
run_as: [],
},
kibana: [
{
spaces: ['*'],
base: [],
// @ts-expect-error TypeScript doesn't distinguish between missing and
// undefined props yet
feature: features,
},
],
};
};

0 comments on commit dd6c75d

Please sign in to comment.