[8.8] [Security Solution][Endpoint] Fix error on security solution UI (#157843) (#158709)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[Security Solution][Endpoint] Fix error on security solution UI
(#157843)](https://github.com/elastic/kibana/pull/157843)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"David
Sánchez","email":"david.sanchezsoler@elastic.co"},"sourceCommit":{"committedDate":"2023-05-31T09:49:47Z","message":"[Security
Solution][Endpoint] Fix error on security solution UI (#157843)\n\n##
Summary\r\nFixes:
https://github.com/elastic/kibana/issues/149807\r\n\r\n- Check for
current user before getting privileges, if no user, it uses\r\nthe
initial state (everything set to false), else if there is
an\r\nauthenticated user, then it gets privileges from
capabilities.\r\n- Adds unit test cases.\r\n\r\nSee comments in file
changes for more info.\r\n\r\nIn order to test that, you have to disable
the `security` flag:\r\n`xpack.security.enabled=false` in
elasticsearch.\r\n- You shouldn't see any JS UI error when navigating
through security\r\nsolution plugin.\r\n- You shouldn't see any endpoint
link (Endpoint list, Trusted apps,\r\nEvent filters, etc.).\r\n- When
accessing to any of the above directly by url, you should see
the\r\nmissing privileges page
instead.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"e0d0f98dfe40dee4179cbf7bb0ecc4d46978a197","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:Defend
Workflows","v8.9.0","v8.8.1"],"number":157843,"url":"https://github.com/elastic/kibana/pull/157843","mergeCommit":{"message":"[Security
Solution][Endpoint] Fix error on security solution UI (#157843)\n\n##
Summary\r\nFixes:
https://github.com/elastic/kibana/issues/149807\r\n\r\n- Check for
current user before getting privileges, if no user, it uses\r\nthe
initial state (everything set to false), else if there is
an\r\nauthenticated user, then it gets privileges from
capabilities.\r\n- Adds unit test cases.\r\n\r\nSee comments in file
changes for more info.\r\n\r\nIn order to test that, you have to disable
the `security` flag:\r\n`xpack.security.enabled=false` in
elasticsearch.\r\n- You shouldn't see any JS UI error when navigating
through security\r\nsolution plugin.\r\n- You shouldn't see any endpoint
link (Endpoint list, Trusted apps,\r\nEvent filters, etc.).\r\n- When
accessing to any of the above directly by url, you should see
the\r\nmissing privileges page
instead.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"e0d0f98dfe40dee4179cbf7bb0ecc4d46978a197"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/157843","number":157843,"mergeCommit":{"message":"[Security
Solution][Endpoint] Fix error on security solution UI (#157843)\n\n##
Summary\r\nFixes:
https://github.com/elastic/kibana/issues/149807\r\n\r\n- Check for
current user before getting privileges, if no user, it uses\r\nthe
initial state (everything set to false), else if there is
an\r\nauthenticated user, then it gets privileges from
capabilities.\r\n- Adds unit test cases.\r\n\r\nSee comments in file
changes for more info.\r\n\r\nIn order to test that, you have to disable
the `security` flag:\r\n`xpack.security.enabled=false` in
elasticsearch.\r\n- You shouldn't see any JS UI error when navigating
through security\r\nsolution plugin.\r\n- You shouldn't see any endpoint
link (Endpoint list, Trusted apps,\r\nEvent filters, etc.).\r\n- When
accessing to any of the above directly by url, you should see
the\r\nmissing privileges page
instead.\r\n\r\n---------\r\n\r\nCo-authored-by: Kibana Machine
<42973632+kibanamachine@users.noreply.github.com>","sha":"e0d0f98dfe40dee4179cbf7bb0ecc4d46978a197"}},{"branch":"8.8","label":"v8.8.1","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: David Sánchez <david.sanchezsoler@elastic.co>
This commit is contained in:
Kibana Machine 2023-05-31 07:49:18 -04:00 committed by GitHub
parent c26fcf79cd
commit 9240a6ee79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 14 deletions

View file

@ -208,6 +208,49 @@ describe('Endpoint Authz service', () => {
expect(authz[auth]).toBe(false);
});
it.each<[EndpointAuthzKeyList[number], string[]]>([
['canWriteEndpointList', ['writeEndpointList']],
['canReadEndpointList', ['writeEndpointList', 'readEndpointList']],
['canWritePolicyManagement', ['writePolicyManagement']],
['canReadPolicyManagement', ['writePolicyManagement', 'readPolicyManagement']],
['canWriteActionsLogManagement', ['writeActionsLogManagement']],
['canReadActionsLogManagement', ['writeActionsLogManagement', 'readActionsLogManagement']],
[
'canAccessEndpointActionsLogManagement',
['writeActionsLogManagement', 'readActionsLogManagement'],
],
['canIsolateHost', ['writeHostIsolation']],
['canUnIsolateHost', ['writeHostIsolation']],
['canKillProcess', ['writeProcessOperations']],
['canSuspendProcess', ['writeProcessOperations']],
['canGetRunningProcesses', ['writeProcessOperations']],
['canWriteExecuteOperations', ['writeExecuteOperations']],
['canWriteFileOperations', ['writeFileOperations']],
['canWriteTrustedApplications', ['writeTrustedApplications']],
['canReadTrustedApplications', ['writeTrustedApplications', 'readTrustedApplications']],
['canWriteHostIsolationExceptions', ['writeHostIsolationExceptions']],
[
'canReadHostIsolationExceptions',
['writeHostIsolationExceptions', 'readHostIsolationExceptions'],
],
['canWriteBlocklist', ['writeBlocklist']],
['canReadBlocklist', ['writeBlocklist', 'readBlocklist']],
['canWriteEventFilters', ['writeEventFilters']],
['canReadEventFilters', ['writeEventFilters', 'readEventFilters']],
// all dependent privileges are false and so it should be false
['canAccessResponseConsole', responseConsolePrivileges],
])(
'%s should be false if `packagePrivilege.%s` is `false` and user roles is undefined',
(auth, privileges) => {
// read permission checks for write || read so we need to set both to false
privileges.forEach((privilege) => {
fleetAuthz.packagePrivileges!.endpoint.actions[privilege].executePackageAction = false;
});
const authz = calculateEndpointAuthz(licenseService, fleetAuthz, undefined, true);
expect(authz[auth]).toBe(false);
}
);
it.each(responseConsolePrivileges)(
'canAccessResponseConsole should be true if %s for CONSOLE privileges is true',
(responseConsolePrivilege) => {

View file

@ -26,7 +26,7 @@ import type { MaybeImmutable } from '../../types';
export function hasKibanaPrivilege(
fleetAuthz: FleetAuthz,
isEndpointRbacEnabled: boolean,
isSuperuser: boolean,
isSuperuser: boolean = false,
privilege: keyof typeof ENDPOINT_PRIVILEGES
): boolean {
// user is superuser, always return true
@ -60,7 +60,7 @@ export function hasKibanaPrivilege(
export const calculateEndpointAuthz = (
licenseService: LicenseService,
fleetAuthz: FleetAuthz,
userRoles: MaybeImmutable<string[]>,
userRoles: MaybeImmutable<string[]> = [],
isEndpointRbacEnabled: boolean = false,
hasHostIsolationExceptionsItems: boolean = false
): EndpointAuthz => {

View file

@ -95,6 +95,13 @@ describe('When using useEndpointPrivileges hook', () => {
expect(result.current).toEqual(getEndpointPrivilegesInitialStateMock());
});
it('should return initial state when no user authz', async () => {
(useCurrentUser as jest.Mock).mockReturnValue({});
render();
expect(result.current).toEqual({ ...getEndpointPrivilegesInitialState(), loading: false });
});
it.each([
['HIE exist', true],
['No HIE exist', false],

View file

@ -6,6 +6,7 @@
*/
import { useEffect, useMemo, useState } from 'react';
import { isEmpty } from 'lodash';
import { useIsMounted } from '@kbn/securitysolution-hook-utils';
import { checkArtifactHasData } from '../../../../management/services/exceptions_list/check_artifact_has_data';
import { HostIsolationExceptionsApiClient } from '../../../../management/pages/host_isolation_exceptions/host_isolation_exceptions_api_client';
@ -61,7 +62,7 @@ export const useEndpointPrivileges = (): Immutable<EndpointPrivileges> => {
const privilegeList: EndpointPrivileges = Object.freeze({
loading,
...(!loading && fleetAuthz
...(!loading && fleetAuthz && !isEmpty(user)
? calculateEndpointAuthz(
licenseService,
fleetAuthz,

View file

@ -50,12 +50,15 @@ describe('links', () => {
const getPlugins = (
roles: string[],
fleetAuthzOverrides: DeepPartial<FleetAuthz> = {}
fleetAuthzOverrides: DeepPartial<FleetAuthz> = {},
noUserAuthz: boolean = false
): StartPlugins => {
return {
security: {
authc: {
getCurrentUser: jest.fn().mockReturnValue({ roles }),
getCurrentUser: noUserAuthz
? jest.fn().mockReturnValue('')
: jest.fn().mockReturnValue({ roles }),
},
},
fleet: {
@ -87,6 +90,24 @@ describe('links', () => {
expect(filteredLinks).toEqual(links);
});
it('should not return any endpoint management link for user with all sub-feature privileges when no user authz', async () => {
const filteredLinks = await getManagementFilteredLinks(
coreMockStarted,
getPlugins([], {}, true)
);
expect(filteredLinks).toEqual(
getLinksWithout(
SecurityPageName.blocklist,
SecurityPageName.endpoints,
SecurityPageName.eventFilters,
SecurityPageName.hostIsolationExceptions,
SecurityPageName.policies,
SecurityPageName.responseActionsHistory,
SecurityPageName.trustedApps
)
);
});
describe('Action Logs', () => {
it('should return all but response actions link when no actions log access', async () => {
(calculateEndpointAuthz as jest.Mock).mockReturnValue(

View file

@ -259,6 +259,7 @@ export const getManagementFilteredLinks = async (
// may see failed HTTP requests in the browser console. This is the reason that
// `hasKibanaPrivilege()` is used below.
if (
currentUser &&
!isPlatinumPlus &&
fleetAuthz &&
hasKibanaPrivilege(
@ -281,15 +282,16 @@ export const getManagementFilteredLinks = async (
canReadEventFilters,
canReadBlocklist,
canReadPolicyManagement,
} = fleetAuthz
? calculateEndpointAuthz(
licenseService,
fleetAuthz,
currentUser.roles,
isEndpointRbacEnabled,
hasHostIsolationExceptions
)
: getEndpointAuthzInitialState();
} =
fleetAuthz && currentUser
? calculateEndpointAuthz(
licenseService,
fleetAuthz,
currentUser.roles,
isEndpointRbacEnabled,
hasHostIsolationExceptions
)
: getEndpointAuthzInitialState();
if (!canReadEndpointList) {
linksToExclude.push(SecurityPageName.endpoints);