Skip to content

Commit 5922872

Browse files
committed
Refactor esql generation and helpers
1 parent 3d796a2 commit 5922872

File tree

12 files changed

+532
-209
lines changed

12 files changed

+532
-209
lines changed

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/components/privileged_user_activity/esql_source_query.ts

Lines changed: 0 additions & 178 deletions
This file was deleted.

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/components/privileged_user_activity/hooks.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,14 @@ import {
2121
buildAuthenticationsColumns,
2222
} from './columns';
2323
import { getLensAttributes } from './get_lens_attributes';
24-
import {
25-
getAccountSwitchesEsqlSource,
26-
getAuthenticationsEsqlSource,
27-
getGrantedRightsEsqlSource,
28-
} from './esql_source_query';
2924
import {
3025
ACCOUNT_SWITCH_STACK_BY,
3126
AUTHENTICATIONS_STACK_BY,
3227
GRANTED_RIGHTS_STACK_BY,
3328
} from './constants';
29+
import { getAuthenticationsEsqlSource } from '../../queries/authentications_esql_query';
30+
import { getAccountSwitchesEsqlSource } from '../../queries/account_switches_esql_query';
31+
import { getGrantedRightsEsqlSource } from '../../queries/granted_rights_esql_query';
3432

3533
const toggleOptionsConfig = {
3634
[VisualizationToggleOptions.GRANTED_RIGHTS]: {
@@ -87,11 +85,17 @@ export const usePrivilegedUserActivityParams = (
8785
[selectedToggleOption, openRightPanel]
8886
);
8987

88+
const hasLoadedDependencies = useMemo(
89+
() => Boolean(spaceId && indexPattern && fields),
90+
[spaceId, indexPattern, fields]
91+
);
92+
9093
return {
9194
getLensAttributes,
9295
generateVisualizationQuery,
9396
generateTableQuery,
9497
columns,
98+
hasLoadedDependencies,
9599
};
96100
};
97101

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/components/privileged_user_activity/index.tsx

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import {
99
EuiButtonGroup,
10+
EuiCallOut,
1011
EuiFlexGroup,
1112
EuiFlexItem,
1213
EuiPanel,
@@ -47,10 +48,14 @@ export const UserActivityPrivilegedUsersPanel: React.FC<{
4748
VisualizationToggleOptions.GRANTED_RIGHTS
4849
);
4950

50-
const { getLensAttributes, columns, generateVisualizationQuery, generateTableQuery } =
51-
usePrivilegedUserActivityParams(selectedToggleOption, sourcererDataView);
51+
const {
52+
getLensAttributes,
53+
columns,
54+
generateVisualizationQuery,
55+
generateTableQuery,
56+
hasLoadedDependencies,
57+
} = usePrivilegedUserActivityParams(selectedToggleOption, sourcererDataView);
5258
const stackByOptions = useStackByOptions(selectedToggleOption);
53-
5459
const setSelectedChartOptionCallback = useCallback(
5560
(event: React.ChangeEvent<HTMLSelectElement>) => {
5661
setSelectedStackByOption(
@@ -118,7 +123,7 @@ export const UserActivityPrivilegedUsersPanel: React.FC<{
118123
</EuiFlexItem>
119124
</EuiFlexGroup>
120125
<EuiSpacer size="m" />
121-
{generateVisualizationQuery && generateTableQuery && (
126+
{generateVisualizationQuery && generateTableQuery ? (
122127
<EsqlDashboardPanel<TableItemType>
123128
title={TITLE}
124129
stackByField={selectedStackByOption.value}
@@ -130,6 +135,25 @@ export const UserActivityPrivilegedUsersPanel: React.FC<{
130135
pageSize={PAGE_SIZE}
131136
showInspectTable={true}
132137
/>
138+
) : (
139+
// If dependencies are loaded but the query generation functions are not available, show an error message
140+
hasLoadedDependencies && (
141+
<EuiCallOut
142+
title={
143+
<FormattedMessage
144+
id="xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.missingMappings.errorTitle"
145+
defaultMessage="There was a problem rendering the visualization"
146+
/>
147+
}
148+
color="warning"
149+
iconType="error"
150+
>
151+
<FormattedMessage
152+
id="xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.userActivity.missingMappings.errorMessage"
153+
defaultMessage="The required fields are not present in the data view."
154+
/>
155+
</EuiCallOut>
156+
)
133157
)}
134158
</>
135159
)}

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/components/risk_level_panel/hooks.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import type { RiskLevelsTableItem, RiskLevelsPrivilegedUsersQueryResult } from '
1919
import { RiskScoreLevel } from '../../../severity/common';
2020
import type { RiskSeverity } from '../../../../../../common/search_strategy';
2121
import { esqlResponseToRecords } from '../../../../../common/utils/esql';
22-
import { getRiskLevelsPrivilegedUsersQueryBody } from './esql_query';
22+
import { getRiskLevelsPrivilegedUsersQueryBody } from '../../queries/risk_level_esql_query';
2323

2424
export const useRiskLevelsPrivilegedUserQuery = ({
2525
skip,

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/components/risk_level_panel/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ import { HeaderSection } from '../../../../../common/components/header_section';
2323
import { InspectButtonContainer } from '../../../../../common/components/inspect';
2424
import { SEVERITY_UI_SORT_ORDER } from '../../../../common';
2525
import { useRiskScoreFillColor } from '../../../risk_score_donut_chart/use_risk_score_fill_color';
26-
import { DONUT_CHART_HEIGHT, RISK_LEVELS_PRIVILEGED_USERS_QUERY_ID } from './esql_query';
26+
import { RISK_LEVELS_PRIVILEGED_USERS_QUERY_ID } from '../../queries/risk_level_esql_query';
2727
import { useRiskLevelsPrivilegedUserQuery, useRiskLevelsTableColumns } from './hooks';
2828

2929
const TITLE = i18n.translate(
3030
'xpack.securitySolution.entityAnalytics.privilegedUserMonitoring.riskLevels.title',
3131
{ defaultMessage: 'Risk levels of privileged users' }
3232
);
3333

34+
export const DONUT_CHART_HEIGHT = 160;
35+
3436
export const RiskLevelsPrivilegedUsersPanel: React.FC<{ spaceId: string }> = ({ spaceId }) => {
3537
const fillColor = useRiskScoreFillColor();
3638
const { toggleStatus, setToggleStatus } = useQueryToggle(RISK_LEVELS_PRIVILEGED_USERS_QUERY_ID);

x-pack/solutions/security/plugins/security_solution/public/entity_analytics/components/privileged_user_monitoring/helpers.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { DataViewFieldMap } from '@kbn/data-views-plugin/common';
9+
import { getPrivilegedMonitorUsersJoin } from './helpers';
10+
11+
export const getAccountSwitchesEsqlSource = (
12+
namespace: string,
13+
indexPattern: string,
14+
fields: DataViewFieldMap
15+
) => {
16+
return `FROM ${indexPattern} METADATA _id, _index
17+
${getPrivilegedMonitorUsersJoin(namespace)}
18+
| WHERE process.command_line.caseless RLIKE "(su|sudo su|sudo -i|sudo -s|ssh [^@]+@[^\s]+)"
19+
| RENAME process.command_line.caseless 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
20+
| KEEP @timestamp, privileged_user, host_ip, target_user, group_name, command_process, _id, _index`;
21+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
import type { DataViewFieldMap } from '@kbn/data-views-plugin/common';
9+
import { getPrivilegedMonitorUsersJoin, removeInvalidForkBranchesFromESQL } from './helpers';
10+
11+
// TODO Verify if we can improve the type field logic https://github.com/elastic/security-team/issues/12713
12+
export const getAuthenticationsEsqlSource = (
13+
namespace: string,
14+
indexPattern: string,
15+
fields: DataViewFieldMap
16+
) =>
17+
removeInvalidForkBranchesFromESQL(
18+
fields,
19+
`FROM ${indexPattern} METADATA _id, _index
20+
${getPrivilegedMonitorUsersJoin(namespace)}
21+
| WHERE user.name IS NOT NULL
22+
| FORK
23+
(
24+
WHERE event.dataset == "okta.system"
25+
| EVAL event_combined = COALESCE(event.action, okta.event_type, event.category)
26+
| WHERE to_lower(event_combined) RLIKE ".*?(authn|authentication|sso|mfa|token.grant|authorize.code|session.start|unauth_app_access_attempt|evaluate_sign_on|verify_push).*?"
27+
| EVAL result = okta.outcome.result
28+
| EVAL destination = okta.target.display_name
29+
| EVAL source = event.module
30+
| EVAL host_ip = source.ip
31+
| EVAL url = okta.debug_context.debug_data.url
32+
| EVAL type = CASE(
33+
STARTS_WITH(url, "/api/v1/authn"), "Direct",
34+
STARTS_WITH(url, "/oauth2/v1/authorize") OR STARTS_WITH(url, "/oauth2/v1/token") OR
35+
LOCATE(url, "/sso/saml") > 0, "Federated",
36+
null)
37+
)
38+
(
39+
WHERE event.dataset != "okta.system" AND event.category == "authentication"
40+
| EVAL result = event.outcome
41+
| EVAL source = host.os.name
42+
| EVAL type = "Direct"
43+
| EVAL destination = host.name
44+
| EVAL host_ip = host.ip
45+
)
46+
| RENAME user.name as privileged_user
47+
| KEEP @timestamp, privileged_user, source, host_ip, result, destination, _id, _index, event.outcome, type`
48+
);

0 commit comments

Comments
 (0)