Skip to content

Commit

Permalink
[Security Solution][Endpoint] Hide/show add endpoint event filters ac…
Browse files Browse the repository at this point in the history
…tion from an endpoint event depending on RBAC privileges (#144989)

## Summary

Hides/shows `Add endpoint event filter` option in event context menu and
event details flyout depending on the RBAC privileges.


### With `all` event filters privileges

![event filters with
privileges](https://user-images.githubusercontent.com/15727784/201128159-51058de9-1cdc-4bc1-8e1d-70f80678239a.gif)



### With `read` and `none` event filters privileges

![event filters no
privileges](https://user-images.githubusercontent.com/15727784/201128157-ff719001-9599-492c-a650-93ead81e1e06.gif)





### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
dasansol92 and kibanamachine authored Nov 21, 2022
1 parent cc50e51 commit 9f700e5
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,11 @@ describe('Alert table context menu', () => {
ecsRowData: { ...ecsRowData, agent: { type: ['endpoint'] }, event: { kind: ['event'] } },
};

describe('when users can access endpoint management', () => {
describe('when users has write event filters privilege', () => {
beforeEach(() => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canAccessEndpointManagement: true },
endpointPrivileges: { loading: false, canWriteEventFilters: true },
});
});

Expand Down Expand Up @@ -246,38 +246,36 @@ describe('Alert table context menu', () => {
});
});

describe('when users can NOT access endpoint management', () => {
describe("when users don't have write event filters privilege", () => {
beforeEach(() => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canAccessEndpointManagement: false },
endpointPrivileges: { loading: false, canWriteEventFilters: false },
});
});

test('it disables AddEndpointEventFilter when timeline id is host events page but cannot acces endpoint management', () => {
test('it removes AddEndpointEventFilter option when timeline id is host events page but does not has write event filters privilege', () => {
const wrapper = mount(
<AlertContextMenu {...endpointEventProps} scopeId={TableId.hostsPageEvents} />,
{
wrappingComponent: TestProviders,
}
);

wrapper.find(actionMenuButton).simulate('click');
expect(wrapper.find(addEndpointEventFilterButton).first().exists()).toEqual(true);
expect(wrapper.find(addEndpointEventFilterButton).first().props().disabled).toEqual(true);
// Entire actionMenuButton is removed as there is no option available
expect(wrapper.find(actionMenuButton).first().exists()).toEqual(false);
});

test('it disables AddEndpointEventFilter when timeline id is user events page but cannot acces endpoint management', () => {
test('it removes AddEndpointEventFilter option when timeline id is user events page but does not has write event filters privilege', () => {
const wrapper = mount(
<AlertContextMenu {...endpointEventProps} scopeId={TableId.usersPageEvents} />,
{
wrappingComponent: TestProviders,
}
);

wrapper.find(actionMenuButton).simulate('click');
expect(wrapper.find(addEndpointEventFilterButton).first().exists()).toEqual(true);
expect(wrapper.find(addEndpointEventFilterButton).first().props().disabled).toEqual(true);
// Entire actionMenuButton is removed as there is no option available
expect(wrapper.find(actionMenuButton).first().exists()).toEqual(false);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps & PropsFromRedux
isInDetections,
});

const { loading: canAccessEndpointManagementLoading, canAccessEndpointManagement } =
const { loading: endpointPrivilegesLoading, canWriteEventFilters } =
useUserPrivileges().endpointPrivileges;
const canCreateEndpointEventFilters = useMemo(
() => !canAccessEndpointManagementLoading && canAccessEndpointManagement,
[canAccessEndpointManagement, canAccessEndpointManagementLoading]
() => !endpointPrivilegesLoading && canWriteEventFilters,
[canWriteEventFilters, endpointPrivilegesLoading]
);

const alertStatus = get(0, ecsRowData?.kibana?.alert?.workflow_status) as Status | undefined;
Expand Down Expand Up @@ -194,8 +194,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps & PropsFromRedux
});
const { eventFilterActionItems } = useEventFilterAction({
onAddEventFilterClick: handleOnAddEventFilterClick,
disabled:
!isEndpointEvent || !canCreateEndpointEventFilters || !scopeIdAllowsAddEndpointEventFilter,
disabled: !isEndpointEvent || !scopeIdAllowsAddEndpointEventFilter,
tooltipMessage: !scopeIdAllowsAddEndpointEventFilter
? i18n.ACTION_ADD_EVENT_FILTER_DISABLED_TOOLTIP
: undefined,
Expand Down Expand Up @@ -227,7 +226,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps & PropsFromRedux
]
: [
...addToCaseActionItems,
...eventFilterActionItems,
...(canCreateEndpointEventFilters ? eventFilterActionItems : []),
...(agentId ? osqueryActionItems : []),
],
[
Expand All @@ -240,6 +239,7 @@ const AlertContextMenuComponent: React.FC<AlertContextMenuProps & PropsFromRedux
osqueryActionItems,
alertDetailsActionItems,
eventFilterActionItems,
canCreateEndpointEventFilters,
]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,11 @@ describe('take action dropdown', () => {
setAlertDetailsDataMockToEvent();
});

test('should enable the "Add Endpoint event filter" button if provided endpoint event', async () => {
test('should enable the "Add Endpoint event filter" button if provided endpoint event and has right privileges', async () => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canWriteEventFilters: true },
});
wrapper = mount(
<TestProviders>
<TakeActionDropdown {...defaultProps} />
Expand All @@ -334,10 +338,10 @@ describe('take action dropdown', () => {
});
});

test('should disable the "Add Endpoint event filter" button if no endpoint management privileges', async () => {
test('should hide the "Add Endpoint event filter" button if no write event filters privileges', async () => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canAccessEndpointManagement: false },
endpointPrivileges: { loading: false, canWriteEventFilters: false },
});
wrapper = mount(
<TestProviders>
Expand All @@ -346,9 +350,7 @@ describe('take action dropdown', () => {
);
wrapper.find('button[data-test-subj="take-action-dropdown-btn"]').simulate('click');
await waitFor(() => {
expect(
wrapper.find('[data-test-subj="add-event-filter-menu-item"]').first().getDOMNode()
).toBeDisabled();
expect(wrapper.exists('[data-test-subj="add-event-filter-menu-item"]')).toBeFalsy();
});
});

Expand Down Expand Up @@ -473,10 +475,10 @@ describe('take action dropdown', () => {
});
});

it('should not display the button if user is not allowed to manage endpoints', async () => {
it('should not display the button if user is not allowed to write event filters', async () => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canAccessEndpointManagement: false },
endpointPrivileges: { loading: false, canWriteEventFilters: false },
});
render();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ export const TakeActionDropdown = React.memo(
scopeId,
}: TakeActionDropdownProps) => {
const tGridEnabled = useIsExperimentalFeatureEnabled('tGridEnabled');
const { loading: canAccessEndpointManagementLoading, canAccessEndpointManagement } =
const { loading: endpointPrivilegesLoading, canWriteEventFilters } =
useUserPrivileges().endpointPrivileges;

const canCreateEndpointEventFilters = useMemo(
() => !canAccessEndpointManagementLoading && canAccessEndpointManagement,
[canAccessEndpointManagement, canAccessEndpointManagementLoading]
() => !endpointPrivilegesLoading && canWriteEventFilters,
[canWriteEventFilters, endpointPrivilegesLoading]
);
const { osquery } = useKibana().services;

Expand Down Expand Up @@ -168,7 +168,6 @@ export const TakeActionDropdown = React.memo(

const { eventFilterActionItems } = useEventFilterAction({
onAddEventFilterClick: handleOnAddEventFilterClick,
disabled: !isEndpointEvent || !canCreateEndpointEventFilters,
});

const onMenuItemClick = useCallback(() => {
Expand Down Expand Up @@ -210,12 +209,13 @@ export const TakeActionDropdown = React.memo(
() =>
!isEvent && actionsData.ruleId
? [...statusActionItems, ...exceptionActionItems]
: isEndpointEvent
: isEndpointEvent && canCreateEndpointEventFilters
? eventFilterActionItems
: [],
[
eventFilterActionItems,
isEndpointEvent,
canCreateEndpointEventFilters,
exceptionActionItems,
statusActionItems,
isEvent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ import {
GuidedOnboardingTourStep,
SecurityTourStep,
} from '../../../../../common/components/guided_onboarding_tour/tour_step';
import { initialUserPrivilegesState as mockInitialUserPrivilegesState } from '../../../../../common/components/user_privileges/user_privileges_context';
import { useUserPrivileges } from '../../../../../common/components/user_privileges';
import { SecurityStepId } from '../../../../../common/components/guided_onboarding_tour/tour_config';

jest.mock('../../../../../common/components/user_privileges');
jest.mock('../../../../../common/components/guided_onboarding_tour');
jest.mock('../../../../../detections/components/user_info', () => ({
useUserData: jest.fn().mockReturnValue([{ canUserCRUD: true, hasIndexWrite: true }]),
Expand Down Expand Up @@ -268,6 +271,12 @@ describe('Actions', () => {
});

describe('Alert context menu enabled?', () => {
beforeEach(() => {
(useUserPrivileges as jest.Mock).mockReturnValue({
...mockInitialUserPrivilegesState(),
endpointPrivileges: { loading: false, canWriteEventFilters: true },
});
});
test('it disables for eventType=raw', () => {
const wrapper = mount(
<TestProviders>
Expand Down

0 comments on commit 9f700e5

Please sign in to comment.