[Security Solution] Use useEndpointPrivileges instead of checking the license directly (#116142)

* Use useEndpointPrivileges instead of checking the license directly

* Use the correct privilege key

* rename variable

* Skips flaky test

* Remove skip

* Remove extra dependency

* Add back entries check

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Esteban Beltran 2021-10-30 01:01:48 +02:00 committed by GitHub
parent 347c138bc0
commit 107661129d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 32 deletions

View file

@ -4,33 +4,35 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { useLicense } from '../../../../common/hooks/use_license';
import { useCanSeeHostIsolationExceptionsMenu } from './hooks';
import { renderHook } from '@testing-library/react-hooks';
import { TestProviders } from '../../../../common/mock';
import { getHostIsolationExceptionSummary } from '../service';
import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint';
jest.mock('../../../../common/hooks/use_license');
jest.mock('../service');
jest.mock('../../../../common/components/user_privileges/endpoint/use_endpoint_privileges');
const getHostIsolationExceptionSummaryMock = getHostIsolationExceptionSummary as jest.Mock;
describe('host isolation exceptions hooks', () => {
const isPlatinumPlusMock = useLicense().isPlatinumPlus as jest.Mock;
const useEndpointPrivilegesMock = useEndpointPrivileges as jest.Mock;
describe('useCanSeeHostIsolationExceptionsMenu', () => {
beforeEach(() => {
isPlatinumPlusMock.mockReset();
useEndpointPrivilegesMock.mockReset();
});
it('should return true if the license is platinum plus', () => {
isPlatinumPlusMock.mockReturnValue(true);
it('should return true if has the correct privileges', () => {
useEndpointPrivilegesMock.mockReturnValue({ canIsolateHost: true });
const { result } = renderHook(() => useCanSeeHostIsolationExceptionsMenu(), {
wrapper: TestProviders,
});
expect(result.current).toBe(true);
});
it('should return false if the license is lower platinum plus and there are not existing host isolation items', () => {
isPlatinumPlusMock.mockReturnValue(false);
it('should return false if does not have privileges and there are not existing host isolation items', () => {
useEndpointPrivilegesMock.mockReturnValue({ canIsolateHost: false });
getHostIsolationExceptionSummaryMock.mockReturnValueOnce({ total: 0 });
const { result } = renderHook(() => useCanSeeHostIsolationExceptionsMenu(), {
wrapper: TestProviders,
@ -38,8 +40,8 @@ describe('host isolation exceptions hooks', () => {
expect(result.current).toBe(false);
});
it('should return true if the license is lower platinum plus and there are existing host isolation items', async () => {
isPlatinumPlusMock.mockReturnValue(false);
it('should return true if does not have privileges and there are existing host isolation items', async () => {
useEndpointPrivilegesMock.mockReturnValue({ canIsolateHost: false });
getHostIsolationExceptionSummaryMock.mockReturnValueOnce({ total: 11 });
const { result, waitForNextUpdate } = renderHook(
() => useCanSeeHostIsolationExceptionsMenu(),

View file

@ -8,7 +8,7 @@ import { useCallback, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { useHttp } from '../../../../common/lib/kibana/hooks';
import { useLicense } from '../../../../common/hooks/use_license';
import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint';
import { State } from '../../../../common/store';
import {
MANAGEMENT_STORE_GLOBAL_NAMESPACE,
@ -42,30 +42,30 @@ export function useHostIsolationExceptionsNavigateCallback() {
/**
* Checks if the current user should be able to see the host isolation exceptions
* menu item based on their current license level and existing excepted items.
* menu item based on their current privileges
*/
export function useCanSeeHostIsolationExceptionsMenu() {
const license = useLicense();
const http = useHttp();
const privileges = useEndpointPrivileges();
const [hasExceptions, setHasExceptions] = useState(license.isPlatinumPlus());
const [canSeeMenu, setCanSeeMenu] = useState(privileges.canIsolateHost);
useEffect(() => {
async function checkIfHasExceptions() {
try {
const summary = await getHostIsolationExceptionSummary(http);
if (summary?.total > 0) {
setHasExceptions(true);
setCanSeeMenu(true);
}
} catch (error) {
// an error will ocurr if the exception list does not exist
setHasExceptions(false);
setCanSeeMenu(false);
}
}
if (!license.isPlatinumPlus()) {
if (!privileges.canIsolateHost) {
checkIfHasExceptions();
}
}, [http, license]);
}, [http, privileges.canIsolateHost]);
return hasExceptions;
return canSeeMenu;
}

View file

@ -14,11 +14,11 @@ import { AppContextTestRender, createAppRootMockRenderer } from '../../../../com
import { isFailedResourceState, isLoadedResourceState } from '../../../state';
import { getHostIsolationExceptionItems } from '../service';
import { HostIsolationExceptionsList } from './host_isolation_exceptions_list';
import { useLicense } from '../../../../common/hooks/use_license';
import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint';
jest.mock('../../../../common/components/user_privileges/endpoint/use_endpoint_privileges');
jest.mock('../service');
jest.mock('../../../../common/hooks/use_license');
jest.mock('../../../../common/components/user_privileges/endpoint/use_endpoint_privileges');
const getHostIsolationExceptionItemsMock = getHostIsolationExceptionItems as jest.Mock;
@ -29,7 +29,7 @@ describe('When on the host isolation exceptions page', () => {
let waitForAction: AppContextTestRender['middlewareSpy']['waitForAction'];
let mockedContext: AppContextTestRender;
const isPlatinumPlusMock = useLicense().isPlatinumPlus as jest.Mock;
const useEndpointPrivilegesMock = useEndpointPrivileges as jest.Mock;
beforeEach(() => {
getHostIsolationExceptionItemsMock.mockReset();
@ -129,11 +129,12 @@ describe('When on the host isolation exceptions page', () => {
});
});
describe('is license platinum plus', () => {
describe('has canIsolateHost privileges', () => {
beforeEach(async () => {
isPlatinumPlusMock.mockReturnValue(true);
useEndpointPrivilegesMock.mockReturnValue({ canIsolateHost: true });
getHostIsolationExceptionItemsMock.mockImplementation(getFoundExceptionListItemSchemaMock);
});
it('should show the create flyout when the add button is pressed', async () => {
render();
await dataReceived();
@ -142,6 +143,7 @@ describe('When on the host isolation exceptions page', () => {
});
expect(renderResult.getByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeTruthy();
});
it('should show the create flyout when the show location is create', async () => {
history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=create`);
render();
@ -151,15 +153,17 @@ describe('When on the host isolation exceptions page', () => {
});
});
describe('is not license platinum plus', () => {
describe('does not have canIsolateHost privileges', () => {
beforeEach(() => {
isPlatinumPlusMock.mockReturnValue(false);
useEndpointPrivilegesMock.mockReturnValue({ canIsolateHost: false });
});
it('should not show the create flyout if the user navigates to the create url', () => {
history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=create`);
render();
expect(renderResult.queryByTestId('hostIsolationExceptionsCreateEditFlyout')).toBeFalsy();
});
it('should not show the create flyout if the user navigates to the edit url', () => {
history.push(`${HOST_ISOLATION_EXCEPTIONS_PATH}?show=edit`);
render();

View file

@ -13,7 +13,6 @@ import { FormattedMessage } from '@kbn/i18n/react';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { ExceptionItem } from '../../../../common/components/exceptions/viewer/exception_item';
import { useLicense } from '../../../../common/hooks/use_license';
import {
getCurrentLocation,
getItemToDelete,
@ -41,6 +40,7 @@ import {
EDIT_HOST_ISOLATION_EXCEPTION_LABEL,
} from './components/translations';
import { getEndpointListPath } from '../../../common/routing';
import { useEndpointPrivileges } from '../../../../common/components/user_privileges/endpoint';
type HostIsolationExceptionPaginatedContent = PaginatedContentProps<
Immutable<ExceptionListItemSchema>,
@ -58,14 +58,14 @@ export const HostIsolationExceptionsList = () => {
const itemToDelete = useHostIsolationExceptionsSelector(getItemToDelete);
const navigateCallback = useHostIsolationExceptionsNavigateCallback();
const history = useHistory();
const license = useLicense();
const showFlyout = license.isPlatinumPlus() && !!location.show;
const privileges = useEndpointPrivileges();
const showFlyout = privileges.canIsolateHost && !!location.show;
useEffect(() => {
if (!isLoading && listItems.length === 0 && !license.isPlatinumPlus()) {
if (!isLoading && listItems.length === 0 && !privileges.canIsolateHost) {
history.replace(getEndpointListPath({ name: 'endpointList' }));
}
}, [history, isLoading, license, listItems.length]);
}, [history, isLoading, listItems.length, privileges.canIsolateHost]);
const handleOnSearch = useCallback(
(query: string) => {
@ -100,7 +100,7 @@ export const HostIsolationExceptionsList = () => {
return {
item: element,
'data-test-subj': `hostIsolationExceptionsCard`,
actions: license.isPlatinumPlus() ? [editAction, deleteAction] : [deleteAction],
actions: privileges.canIsolateHost ? [editAction, deleteAction] : [deleteAction],
};
}
@ -139,7 +139,7 @@ export const HostIsolationExceptionsList = () => {
/>
}
actions={
license.isPlatinumPlus() && listItems.length > 0 ? (
privileges.canIsolateHost && listItems.length > 0 ? (
<EuiButton
fill
iconType="plusInCircle"