Skip to content

Commit

Permalink
[7.x] [Security Solutions][Detection Engine] Adds e2e and unit tests …
Browse files Browse the repository at this point in the history
…for PR #89947  (#89973) (#90091)

* [Security Solutions][Detection Engine] Adds e2e and unit tests for PR #89947  (#89973)

## Summary

Adds e2e and unit tests for PR:
#89947

* Adds e2e tests for create_index
* Adds e2e tests for get_privileges
* Adds unit test for use_privilege_user
* Adds exhaustive switch for the roles in the e2e tests
* Adds some typescript barrel rolls for the .json scripts to make TypeScript a bit more readable when doing imports 
* Fixes some of the types that were not matched up with the recent privilege endpoint

### Checklist

- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios

* Fixes the backport for test to work correctly as the messages are different

* Fixes one permission change issue between versions
  • Loading branch information
FrankHassanabad authored Feb 3, 2021
1 parent b4de7f4 commit 6179ac4
Show file tree
Hide file tree
Showing 18 changed files with 1,292 additions and 44 deletions.
2 changes: 0 additions & 2 deletions x-pack/plugins/security_solution/common/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ export enum ROLES {
platform_engineer = 'platform_engineer',
detections_admin = 'detections_admin',
}

export type RolesType = keyof typeof ROLES;
20 changes: 10 additions & 10 deletions x-pack/plugins/security_solution/cypress/tasks/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import * as yaml from 'js-yaml';
import Url, { UrlObject } from 'url';

import { RolesType } from '../../common/test';
import { ROLES } from '../../common/test';
import { TIMELINE_FLYOUT_BODY } from '../screens/timeline';

/**
Expand Down Expand Up @@ -53,7 +53,7 @@ const LOGIN_API_ENDPOINT = '/internal/security/login';
* @param role string role/user to log in with
* @param route string route to visit
*/
export const getUrlWithRoute = (role: RolesType, route: string) => {
export const getUrlWithRoute = (role: ROLES, route: string) => {
const theUrl = `${Url.format({
auth: `${role}:changeme`,
username: role,
Expand All @@ -73,7 +73,7 @@ export const getCurlScriptEnvVars = () => ({
KIBANA_URL: Cypress.env('KIBANA_URL'),
});

export const postRoleAndUser = (role: RolesType) => {
export const postRoleAndUser = (role: ROLES) => {
const env = getCurlScriptEnvVars();
const detectionsRoleScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/post_detections_role.sh`;
const detectionsRoleJsonPath = `./server/lib/detection_engine/scripts/roles_users/${role}/detections_role.json`;
Expand All @@ -91,7 +91,7 @@ export const postRoleAndUser = (role: RolesType) => {
});
};

export const deleteRoleAndUser = (role: RolesType) => {
export const deleteRoleAndUser = (role: ROLES) => {
const env = getCurlScriptEnvVars();
const detectionsUserDeleteScriptPath = `./server/lib/detection_engine/scripts/roles_users/${role}/delete_detections_user.sh`;

Expand All @@ -101,7 +101,7 @@ export const deleteRoleAndUser = (role: RolesType) => {
});
};

export const loginWithRole = async (role: RolesType) => {
export const loginWithRole = async (role: ROLES) => {
postRoleAndUser(role);
const theUrl = Url.format({
auth: `${role}:changeme`,
Expand Down Expand Up @@ -136,7 +136,7 @@ export const loginWithRole = async (role: RolesType) => {
* To speed the execution of tests, prefer this non-interactive authentication,
* which is faster than authentication via Kibana's interactive login page.
*/
export const login = (role?: RolesType) => {
export const login = (role?: ROLES) => {
if (role != null) {
loginWithRole(role);
} else if (credentialsProvidedByEnvironment()) {
Expand Down Expand Up @@ -217,21 +217,21 @@ const loginViaConfig = () => {
* Authenticates with Kibana, visits the specified `url`, and waits for the
* Kibana global nav to be displayed before continuing
*/
export const loginAndWaitForPage = (url: string, role?: RolesType) => {
export const loginAndWaitForPage = (url: string, role?: ROLES) => {
login(role);
cy.visit(
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))`
);
cy.get('[data-test-subj="headerGlobalNav"]');
};

export const loginAndWaitForPageWithoutDateRange = (url: string, role?: RolesType) => {
export const loginAndWaitForPageWithoutDateRange = (url: string, role?: ROLES) => {
login(role);
cy.visit(role ? getUrlWithRoute(role, url) : url);
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 });
};

export const loginAndWaitForTimeline = (timelineId: string, role?: RolesType) => {
export const loginAndWaitForTimeline = (timelineId: string, role?: ROLES) => {
const route = `/app/security/timelines?timeline=(id:'${timelineId}',isOpen:!t)`;

login(role);
Expand All @@ -240,7 +240,7 @@ export const loginAndWaitForTimeline = (timelineId: string, role?: RolesType) =>
cy.get(TIMELINE_FLYOUT_BODY).should('be.visible');
};

export const waitForPageWithoutDateRange = (url: string, role?: RolesType) => {
export const waitForPageWithoutDateRange = (url: string, role?: ROLES) => {
cy.visit(role ? getUrlWithRoute(role, url) : url);
cy.get('[data-test-subj="headerGlobalNav"]', { timeout: 120000 });
};
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,7 @@ export const mockUserPrivilege: Privilege = {
cluster: {
monitor_ml: true,
manage_ccr: true,
manage_api_key: true,
manage_index_templates: true,
monitor_watcher: true,
monitor_transform: true,
Expand Down Expand Up @@ -1033,6 +1034,7 @@ export const mockUserPrivilege: Privilege = {
write: true,
},
},
application: {},
is_authenticated: true,
has_encryption_key: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface Privilege {
monitor_watcher: boolean;
monitor_transform: boolean;
read_ilm: boolean;
manage_api_key: boolean;
manage_security: boolean;
manage_own_api_key: boolean;
manage_saml: boolean;
Expand Down Expand Up @@ -97,6 +98,7 @@ export interface Privilege {
write: boolean;
};
};
application: {};
is_authenticated: boolean;
has_encryption_key: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { renderHook, act } from '@testing-library/react-hooks';
import { usePrivilegeUser, ReturnPrivilegeUser } from './use_privilege_user';
import * as api from './api';
import { Privilege } from './types';

jest.mock('./api');

Expand Down Expand Up @@ -70,4 +71,156 @@ describe('usePrivilegeUser', () => {
});
});
});

test('returns "hasIndexManage" is false if the privilege does not have cluster manage', async () => {
const privilege: Privilege = {
username: 'soc_manager',
has_all_requested: false,
cluster: {
monitor_ml: false,
manage_ccr: false,
manage_index_templates: false,
monitor_watcher: false,
monitor_transform: false,
read_ilm: false,
manage_api_key: false,
manage_security: false,
manage_own_api_key: false,
manage_saml: false,
all: false,
manage_ilm: false,
manage_ingest_pipelines: false,
read_ccr: false,
manage_rollup: false,
monitor: false,
manage_watcher: false,
manage: false,
manage_transform: false,
manage_token: false,
manage_ml: false,
manage_pipeline: false,
monitor_rollup: false,
transport_client: false,
create_snapshot: false,
},
index: {
'.siem-signals-default': {
all: false,
manage_ilm: true,
read: true,
create_index: true,
read_cross_cluster: false,
index: true,
monitor: true,
delete: true,
manage: true,
delete_index: true,
create_doc: true,
view_index_metadata: true,
create: true,
manage_follow_index: true,
manage_leader_index: true,
maintenance: true,
write: true,
},
},
application: {},
is_authenticated: true,
has_encryption_key: true,
};
const spyOnGetUserPrivilege = jest.spyOn(api, 'getUserPrivilege');
spyOnGetUserPrivilege.mockImplementation(() => Promise.resolve(privilege));
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, ReturnPrivilegeUser>(() =>
usePrivilegeUser()
);
await waitForNextUpdate();
await waitForNextUpdate();
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: false,
hasIndexMaintenance: true,
hasIndexWrite: true,
hasIndexUpdateDelete: true,
isAuthenticated: true,
loading: false,
});
});
});

test('returns "hasIndexManage" is true if the privilege has cluster manage', async () => {
const privilege: Privilege = {
username: 'soc_manager',
has_all_requested: false,
cluster: {
monitor_ml: false,
manage_ccr: false,
manage_index_templates: false,
monitor_watcher: false,
monitor_transform: false,
read_ilm: false,
manage_api_key: false,
manage_security: false,
manage_own_api_key: false,
manage_saml: false,
all: false,
manage_ilm: false,
manage_ingest_pipelines: false,
read_ccr: false,
manage_rollup: false,
monitor: false,
manage_watcher: false,
manage: true,
manage_transform: false,
manage_token: false,
manage_ml: false,
manage_pipeline: false,
monitor_rollup: false,
transport_client: false,
create_snapshot: false,
},
index: {
'.siem-signals-default': {
all: false,
manage_ilm: true,
read: true,
create_index: true,
read_cross_cluster: false,
index: true,
monitor: true,
delete: true,
manage: true,
delete_index: true,
create_doc: true,
view_index_metadata: true,
create: true,
manage_follow_index: true,
manage_leader_index: true,
maintenance: true,
write: true,
},
},
application: {},
is_authenticated: true,
has_encryption_key: true,
};
const spyOnGetUserPrivilege = jest.spyOn(api, 'getUserPrivilege');
spyOnGetUserPrivilege.mockImplementation(() => Promise.resolve(privilege));
await act(async () => {
const { result, waitForNextUpdate } = renderHook<void, ReturnPrivilegeUser>(() =>
usePrivilegeUser()
);
await waitForNextUpdate();
await waitForNextUpdate();
expect(result.current).toEqual({
hasEncryptionKey: true,
hasIndexManage: true,
hasIndexMaintenance: true,
hasIndexWrite: true,
hasIndexUpdateDelete: true,
isAuthenticated: true,
loading: false,
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 detectionsAdminUser from './detections_user.json';
import * as detectionsAdminRole from './detections_role.json';
export { detectionsAdminUser, detectionsAdminRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 hunterUser from './detections_user.json';
import * as hunterRole from './detections_role.json';
export { hunterUser, hunterRole };
Original file line number Diff line number Diff line change
@@ -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.
*/
export * from './detections_admin';
export * from './hunter';
export * from './platform_engineer';
export * from './reader';
export * from './rule_author';
export * from './soc_manager';
export * from './t1_analyst';
export * from './t2_analyst';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 platformEngineerUser from './detections_user.json';
import * as platformEngineerRole from './detections_role.json';
export { platformEngineerUser, platformEngineerRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 readerUser from './detections_user.json';
import * as readerRole from './detections_role.json';
export { readerUser, readerRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 ruleAuthorUser from './detections_user.json';
import * as ruleAuthorRole from './detections_role.json';
export { ruleAuthorUser, ruleAuthorRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 socManagerUser from './detections_user.json';
import * as socManagerRole from './detections_role.json';
export { socManagerUser, socManagerRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 t1AnalystUser from './detections_user.json';
import * as t1AnalystRole from './detections_role.json';
export { t1AnalystUser, t1AnalystRole };
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* 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 t2AnalystUser from './detections_user.json';
import * as t2AnalystRole from './detections_role.json';
export { t2AnalystUser, t2AnalystRole };
Loading

0 comments on commit 6179ac4

Please sign in to comment.