Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const timestampColumn: EuiBasicTableColumn<TableItemType> = {
},
};

const getPrivilegedUserColumn = (fieldName: string) => ({
const getPrivilegedUserColumn = () => ({
field: 'privileged_user',
name: (
<FormattedMessage
Expand All @@ -52,38 +52,25 @@ const getPrivilegedUserColumn = (fieldName: string) => ({
),
width: COLUMN_WIDTHS.privileged_user,
render: (user: string[] | string) =>
user != null
? getRowItemsWithActions({
values: isArray(user) ? user : [user],
// TODO We need a way to filter by several field with an OR expression
// because the ESQL queries several source indices that have different field names
// Issue to extend SecurityCellActions to support this: https://github.com/elastic/security-team/issues/12712
fieldName,
idPrefix: 'privileged-user-monitoring-privileged-user',
render: (item) => <UserName userName={item} scopeId={SCOPE_ID} />,
displayCount: 1,
})
: getEmptyTagValue(),
getRowItemsWithActions({
values: isArray(user) ? user : [user],
fieldName: 'user.name',
idPrefix: 'privileged-user-monitoring-privileged-user',
render: (item) => <UserName userName={item} scopeId={SCOPE_ID} />,
displayCount: 1,
}),
});

const getTargetUserColumn = (fieldName: string) => ({
const getTargetUserColumn = () => ({
field: 'target_user',
name: (
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.columns.targetUser"
defaultMessage="Target user"
/>
),
render: (user: string[] | string) =>
user != null
? getRowItemsWithActions({
values: isArray(user) ? user : [user],
fieldName,
idPrefix: 'privileged-user-monitoring-target-user',
render: (item) => <UserName userName={item} scopeId={SCOPE_ID} />,
displayCount: 1,
})
: getEmptyTagValue(),
render: (user: string) =>
user != null ? <UserName userName={user} scopeId={SCOPE_ID} /> : getEmptyTagValue(),
});

const getIpColumn = (fieldName = 'source.ip') => ({
Expand All @@ -95,15 +82,13 @@ const getIpColumn = (fieldName = 'source.ip') => ({
/>
),
render: (ips: string[] | string) =>
ips != null
? getRowItemsWithActions({
values: isArray(ips) ? ips : [ips],
fieldName,
idPrefix: 'privileged-user-monitoring-ip',
render: (item) => <NetworkDetails ip={item} />,
displayCount: 1,
})
: getEmptyTagValue(),
getRowItemsWithActions({
values: isArray(ips) ? ips : [ips],
fieldName: '', // Dirty hack to disable CellActions, remove this when CellActions support multiple fields
idPrefix: 'privileged-user-monitoring-ip',
render: (item) => <NetworkDetails ip={item} />,
displayCount: 1,
}),
});

const getActionsColumn = (openRightPanel: (props: FlyoutPanelProps) => void) => ({
Expand Down Expand Up @@ -148,8 +133,8 @@ export const buildGrantedRightsColumns = (
): Array<EuiBasicTableColumn<TableItemType>> => [
getActionsColumn(openRightPanel),
timestampColumn,
getPrivilegedUserColumn('user.name'),
getTargetUserColumn('user.target.name'),
getPrivilegedUserColumn(),
getTargetUserColumn(),
{
field: 'group_name',
name: (
Expand All @@ -167,9 +152,9 @@ export const buildAccountSwitchesColumns = (
): Array<EuiBasicTableColumn<TableItemType>> => [
getActionsColumn(openRightPanel),
timestampColumn,
getPrivilegedUserColumn('process.real_user.name'),
getPrivilegedUserColumn(),
{
...getTargetUserColumn('process.group_leader.user.name'),
...getTargetUserColumn(),
name: (
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.columns.targetAccount"
Expand Down Expand Up @@ -203,7 +188,7 @@ export const buildAuthenticationsColumns = (
): Array<EuiBasicTableColumn<TableItemType>> => [
getActionsColumn(openRightPanel),
timestampColumn,
getPrivilegedUserColumn('client.user.name'),
getPrivilegedUserColumn(),
{
field: 'source',
name: (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ jest.mock('../../../../../common/hooks/use_space_id', () => ({
useSpaceId: jest.fn().mockReturnValue('default'),
}));

jest.mock('../../queries/helpers', () => {
const originalModule = jest.requireActual('../../queries/helpers');
return {
...originalModule,
removeInvalidForkBranchesFromESQL: jest.fn((fields, esql) => esql),
};
});

const mockedSourcererDataView = {
title: 'test-*',
fields: {},
Expand Down Expand Up @@ -65,8 +73,6 @@ describe('UserActivityPrivilegedUsersPanel', () => {
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});
// select a visualization that doesn't require dataview fields
fireEvent.click(screen.getByTestId('account_switches'));

expect(screen.getByTestId('esql-dashboard-panel')).toBeInTheDocument();
});
Expand All @@ -84,8 +90,7 @@ describe('UserActivityPrivilegedUsersPanel', () => {
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});
// select a visualization that doesn't require dataview fields
fireEvent.click(screen.getByTestId('account_switches'));

expect(screen.getByText('View all events')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import { SCOPE_ID } from '../../constants';

const COLUMN_WIDTHS = { actions: '5%', '@timestamp': '20%', privileged_user: '15%' };

const getPrivilegedUserColumn = (fieldName: string) => ({
const getPrivilegedUserColumn = () => ({
field: 'user.name',
name: (
<FormattedMessage
Expand All @@ -65,7 +65,7 @@ const getPrivilegedUserColumn = (fieldName: string) => ({
user != null
? getRowItemsWithActions({
values: isArray(user) ? user : [user],
fieldName,
fieldName: 'user.name',
idPrefix: 'privileged-user-monitoring-privileged-user',
render: (item) => <UserName userName={item} scopeId={SCOPE_ID} />,
displayCount: 1,
Expand Down Expand Up @@ -321,7 +321,7 @@ export const buildPrivilegedUsersTableColumns = (
euiTheme: EuiThemeComputed
): Array<EuiBasicTableColumn<TableItemType>> => [
getActionsColumn(openUserFlyout),
getPrivilegedUserColumn('user.name'),
getPrivilegedUserColumn(),
getRiskScoreColumn(euiTheme),
getAssetCriticalityColumn(),
getDataSourceColumn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,28 @@
*/

import type { DataViewFieldMap } from '@kbn/data-views-plugin/common';
import { getPrivilegedMonitorUsersJoin } from './helpers';
import { getPrivilegedMonitorUsersJoin, removeInvalidForkBranchesFromESQL } from './helpers';

export const getAccountSwitchesEsqlSource = (
namespace: string,
indexPattern: string,
fields: DataViewFieldMap
) => {
return `FROM ${indexPattern} METADATA _id, _index
) =>
removeInvalidForkBranchesFromESQL(
fields,
`FROM ${indexPattern} METADATA _id, _index
${getPrivilegedMonitorUsersJoin(namespace)}
| WHERE to_lower(process.command_line) RLIKE "(su|sudo su|sudo -i|sudo -s|ssh [^@]+@[^\s]+)"
| RENAME process.command_line AS command_process, process.group_leader.user.name AS target_user, process.parent.real_group.name AS group_name, process.real_user.name as privileged_user, host.ip AS host_ip
| KEEP @timestamp, privileged_user, host_ip, target_user, group_name, command_process, _id, _index`;
};
| WHERE to_lower(process.command_line) RLIKE "(su .*|su|sudo su|sudo -i|sudo -s|ssh [^@]+@[^\s]+)"
| FORK
(
WHERE event.dataset != "endpoint.events.process" AND event.action =="logged-on"
| EVAL target_user = REPLACE(user.effective.name, "\\\\(.*\\\\)", "")
| EVAL group_name = COALESCE(user.group.name, user.group.id)
| RENAME process.command_line AS command_process, user.name as privileged_user, host.ip AS host_ip
)
(
WHERE event.dataset == "endpoint.events.process"
| RENAME process.command_line AS command_process, process.group_leader.user.name AS target_user, process.parent.real_group.name AS group_name, process.real_user.name as privileged_user, host.ip AS host_ip
)
| KEEP @timestamp, privileged_user, host_ip, target_user, group_name, command_process, _id, _index`
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React, { useCallback, useEffect, useMemo, useReducer } from 'react';
import {
EuiButtonEmpty,
Expand Down Expand Up @@ -40,6 +41,7 @@ import { PrivilegedUserMonitoringManageDataSources } from '../components/privile
import { EmptyPrompt } from '../../common/components/empty_prompt';
import { useDataView } from '../../data_view_manager/hooks/use_data_view';
import { PageLoader } from '../../common/components/page_loader';
import { DataViewManagerScopeName } from '../../data_view_manager/constants';

type PageState =
| { type: 'fetchingEngineStatus' }
Expand Down Expand Up @@ -109,8 +111,8 @@ export const EntityAnalyticsPrivilegedUserMonitoringPage = () => {
sourcererDataView: oldSourcererDataViewSpec,
} = useSourcererDataView();
const newDataViewPickerEnabled = useIsExperimentalFeatureEnabled('newDataViewPickerEnabled');
const { dataView, status } = useDataView();
const { dataViewSpec } = useDataViewSpec();
const { dataView, status } = useDataView(DataViewManagerScopeName.explore);
const { dataViewSpec } = useDataViewSpec(DataViewManagerScopeName.explore); // TODO: newDataViewPicker - this could be left, as the fieldMap spec is actually being used

const isSourcererLoading = useMemo(
() => (newDataViewPickerEnabled ? status !== 'ready' : oldIsSourcererLoading),
Expand Down