Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import { useIntervalForHeatmap } from './pad_heatmap_interval_hooks';
import { getPrivilegedMonitorUsersJoin } from '../../../../helpers';
import type { AnomalyBand } from '../pad_anomaly_bands';
import { getPrivilegedMonitorUsersJoin } from '../../../../queries/helpers';

const getHiddenBandsFilters = (anomalyBands: AnomalyBand[]) => {
const hiddenBands = anomalyBands.filter((each) => each.hidden);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,38 +138,14 @@ describe('columns', () => {
expect(screen.getByText('Console')).toBeInTheDocument();
});

it('renders type column as "Direct" for /api/v1/authn*', () => {
it('renders type column', () => {
const col = columns[4] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('/api/v1/authn/something', baseRecord)}</>, {
render(<>{col.render?.('Direct', baseRecord)}</>, {
wrapper: TestProviders,
});
expect(screen.getByText('Direct')).toBeInTheDocument();
});

it('renders type column as "Federated" for /oauth2/v1/authorize', () => {
const col = columns[4] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('/oauth2/v1/authorize', baseRecord)}</>, { wrapper: TestProviders });
expect(screen.getByText('Federated')).toBeInTheDocument();
});

it('renders type column as "Federated" for /oauth2/v1/token', () => {
const col = columns[4] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('/oauth2/v1/token', baseRecord)}</>, { wrapper: TestProviders });
expect(screen.getByText('Federated')).toBeInTheDocument();
});

it('renders type column as "Federated" for string containing /sso/saml', () => {
const col = columns[4] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('/some/path/sso/saml', baseRecord)}</>, { wrapper: TestProviders });
expect(screen.getByText('Federated')).toBeInTheDocument();
});

it('renders type column as original value for unmatched string', () => {
const col = columns[4] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('/api/v1/authn', baseRecord)}</>, { wrapper: TestProviders });
expect(screen.getByText('Direct')).toBeInTheDocument();
});

it('renders result column with badge', () => {
const col = columns[5] as EuiTableFieldDataColumnType<TableItemType>;
render(<>{col.render?.('success', baseRecord)}</>, { wrapper: TestProviders });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,27 +221,20 @@ export const buildAuthenticationsColumns = (
},
},
{
field: 'url',
field: 'type',
name: (
<FormattedMessage
id="xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.columns.type"
defaultMessage="Type"
/>
),
render: (url?: string) => {
if (!url) {
return getEmptyTagValue();
}

const type = getLoginTypeFromUrl(url);

render: (type?: string) => {
if (!type) {
return getEmptyTagValue();
}

return type;
},
truncateText: true,
},
// TODO Add the column depending on this ticket output https://github.com/elastic/security-team/issues/12713
// {
Expand Down Expand Up @@ -294,25 +287,3 @@ const getResultColor = (value: string) => {
}
return 'default';
};

// TODO Verify if we can improve this logic https://github.com/elastic/security-team/issues/12713
const getLoginTypeFromUrl = (url: string) => {
if (url.startsWith('/api/v1/authn')) {
return i18n.translate(
'xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.columns.type.direct',
{ defaultMessage: 'Direct' }
);
}

if (
url.startsWith('/oauth2/v1/authorize') ||
url.startsWith('/oauth2/v1/token') ||
url.includes('/sso/saml')
) {
return i18n.translate(
'xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.columns.type.federated',
{ defaultMessage: 'Federated' }
);
}
return undefined;
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import React, { useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { useExpandableFlyoutApi } from '@kbn/expandable-flyout';
import type { DataViewSpec } from '@kbn/data-views-plugin/public';
import { useSpaceId } from '../../../../../common/hooks/use_space_id';
import {
generateListESQLQuery,
Expand All @@ -20,16 +21,14 @@ import {
buildAuthenticationsColumns,
} from './columns';
import { getLensAttributes } from './get_lens_attributes';
import {
getAccountSwitchesEsqlSource,
getAuthenticationsEsqlSource,
getGrantedRightsEsqlSource,
} from './esql_source_query';
import {
ACCOUNT_SWITCH_STACK_BY,
AUTHENTICATIONS_STACK_BY,
GRANTED_RIGHTS_STACK_BY,
} from './constants';
import { getAuthenticationsEsqlSource } from '../../queries/authentications_esql_query';
import { getAccountSwitchesEsqlSource } from '../../queries/account_switches_esql_query';
import { getGrantedRightsEsqlSource } from '../../queries/granted_rights_esql_query';

const toggleOptionsConfig = {
[VisualizationToggleOptions.GRANTED_RIGHTS]: {
Expand All @@ -50,13 +49,24 @@ const toggleOptionsConfig = {
};

export const usePrivilegedUserActivityParams = (
selectedToggleOption: VisualizationToggleOptions
selectedToggleOption: VisualizationToggleOptions,
sourcererDataView: DataViewSpec
) => {
const spaceId = useSpaceId();

const indexPattern = sourcererDataView?.title ?? '';
const fields = sourcererDataView?.fields;

const esqlSource = useMemo(
() =>
spaceId ? toggleOptionsConfig[selectedToggleOption].generateEsqlSource(spaceId) : undefined,
[selectedToggleOption, spaceId]
spaceId && indexPattern && fields
? toggleOptionsConfig[selectedToggleOption].generateEsqlSource(
spaceId,
indexPattern,
fields
)
: undefined,
[selectedToggleOption, spaceId, indexPattern, fields]
);

const generateTableQuery = useMemo(
Expand All @@ -75,11 +85,17 @@ export const usePrivilegedUserActivityParams = (
[selectedToggleOption, openRightPanel]
);

const hasLoadedDependencies = useMemo(
() => Boolean(spaceId && indexPattern && fields),
[spaceId, indexPattern, fields]
);

return {
getLensAttributes,
generateVisualizationQuery,
generateTableQuery,
columns,
hasLoadedDependencies,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,64 @@ jest.mock('../../../../../common/hooks/use_space_id', () => ({
useSpaceId: jest.fn().mockReturnValue('default'),
}));

const mockedSourcererDataView = {
title: 'test-*',
fields: {},
};

describe('UserActivityPrivilegedUsersPanel', () => {
it('renders panel title', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});

expect(screen.getByText('Privileged user activity')).toBeInTheDocument();
});

it('renders the toggle button group', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
expect(screen.getByRole('group', { name: /ABOUT_CONTROL_LEGEND/i })).toBeInTheDocument();
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});
expect(
screen.getByRole('group', { name: /Select a visualization to display/i })
).toBeInTheDocument();
});

it('renders the stack by select with options', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});
expect(screen.getByText('Stack by')).toBeInTheDocument();
expect(screen.getByRole('option', { name: 'Privileged user' })).toBeInTheDocument();
expect(screen.getByRole('option', { name: 'Target user' })).toBeInTheDocument();
expect(screen.getByRole('option', { name: 'Granted right' })).toBeInTheDocument();
});

it('renders the EsqlDashboardPanel', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
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();
});

it('changes stack by option when select changes', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
render(<UserActivityPrivilegedUsersPanel sourcererDataView={mockedSourcererDataView} />, {
wrapper: TestProviders,
});
const select = screen.getByRole('combobox');
fireEvent.change(select, { target: { value: 'group_name' } });
expect((select as HTMLSelectElement).value).toBe('group_name');
});

it('renders the "View all events by privileged users" link', () => {
render(<UserActivityPrivilegedUsersPanel />, { wrapper: TestProviders });
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();
});
});
Loading