diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index d77a555991df8..4316b1c033ec6 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -10,6 +10,7 @@ import { ENABLE_CASE_CONNECTOR } from '../../cases/common'; import { metadataTransformPattern } from './endpoint/constants'; export const APP_ID = 'securitySolution'; +export const CASES_FEATURE_ID = 'securitySolutionCases'; export const SERVER_APP_ID = 'siem'; export const APP_NAME = 'Security'; export const APP_ICON = 'securityAnalyticsApp'; diff --git a/x-pack/plugins/security_solution/cypress/integration/cases/privileges.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases/privileges.spec.ts index 4d6c60e93ee20..23016ecc512b1 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases/privileges.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases/privileges.spec.ts @@ -81,6 +81,7 @@ const secAll: Role = { { feature: { siem: ['all'], + securitySolutionCases: ['all'], actions: ['all'], actionsSimulators: ['all'], }, @@ -110,7 +111,8 @@ const secReadCasesAll: Role = { kibana: [ { feature: { - siem: ['minimal_read', 'cases_all'], + siem: ['read'], + securitySolutionCases: ['all'], actions: ['all'], actionsSimulators: ['all'], }, diff --git a/x-pack/plugins/security_solution/public/app/deep_links/index.test.ts b/x-pack/plugins/security_solution/public/app/deep_links/index.test.ts index 5bcc598c7be5e..a3dc6565b19c6 100644 --- a/x-pack/plugins/security_solution/public/app/deep_links/index.test.ts +++ b/x-pack/plugins/security_solution/public/app/deep_links/index.test.ts @@ -8,6 +8,7 @@ import { getDeepLinks, PREMIUM_DEEP_LINK_IDS } from '.'; import { AppDeepLink, Capabilities } from '../../../../../../src/core/public'; import { SecurityPageName } from '../types'; import { mockGlobalState } from '../../common/mock'; +import { CASES_FEATURE_ID } from '../../../common/constants'; const findDeepLink = (id: string, deepLinks: AppDeepLink[]): AppDeepLink | null => deepLinks.reduce((deepLinkFound: AppDeepLink | null, deepLink) => { @@ -58,7 +59,7 @@ describe('deepLinks', () => { it('should return case links for basic license with only read_cases capabilities', () => { const basicLicense = 'basic'; const basicLinks = getDeepLinks(mockGlobalState.app.enableExperimental, basicLicense, { - siem: { read_cases: true, crud_cases: false }, + [CASES_FEATURE_ID]: { read_cases: true, crud_cases: false }, } as unknown as Capabilities); expect(findDeepLink(SecurityPageName.case, basicLinks)).toBeTruthy(); @@ -67,7 +68,7 @@ describe('deepLinks', () => { it('should return case links with NO deepLinks for basic license with only read_cases capabilities', () => { const basicLicense = 'basic'; const basicLinks = getDeepLinks(mockGlobalState.app.enableExperimental, basicLicense, { - siem: { read_cases: true, crud_cases: false }, + [CASES_FEATURE_ID]: { read_cases: true, crud_cases: false }, } as unknown as Capabilities); expect(findDeepLink(SecurityPageName.case, basicLinks)?.deepLinks?.length === 0).toBeTruthy(); }); @@ -75,7 +76,7 @@ describe('deepLinks', () => { it('should return case links with deepLinks for basic license with crud_cases capabilities', () => { const basicLicense = 'basic'; const basicLinks = getDeepLinks(mockGlobalState.app.enableExperimental, basicLicense, { - siem: { read_cases: true, crud_cases: true }, + [CASES_FEATURE_ID]: { read_cases: true, crud_cases: true }, } as unknown as Capabilities); expect( @@ -86,7 +87,7 @@ describe('deepLinks', () => { it('should return NO case links for basic license with NO read_cases capabilities', () => { const basicLicense = 'basic'; const basicLinks = getDeepLinks(mockGlobalState.app.enableExperimental, basicLicense, { - siem: { read_cases: false, crud_cases: false }, + [CASES_FEATURE_ID]: { read_cases: false, crud_cases: false }, } as unknown as Capabilities); expect(findDeepLink(SecurityPageName.case, basicLinks)).toBeFalsy(); diff --git a/x-pack/plugins/security_solution/public/app/deep_links/index.ts b/x-pack/plugins/security_solution/public/app/deep_links/index.ts index e8d4f5d09e5f7..aaa8ce789591f 100644 --- a/x-pack/plugins/security_solution/public/app/deep_links/index.ts +++ b/x-pack/plugins/security_solution/public/app/deep_links/index.ts @@ -48,6 +48,7 @@ import { TRUSTED_APPS_PATH, EVENT_FILTERS_PATH, UEBA_PATH, + CASES_FEATURE_ID, HOST_ISOLATION_EXCEPTIONS_PATH, } from '../../../common/constants'; import { ExperimentalFeatures } from '../../../common/experimental_features'; @@ -362,7 +363,7 @@ export function getDeepLinks( return false; } if (deepLink.id === SecurityPageName.case) { - return capabilities == null || capabilities.siem.read_cases === true; + return capabilities == null || capabilities[CASES_FEATURE_ID].read_cases === true; } if (deepLink.id === SecurityPageName.ueba) { return enableExperimental.uebaEnabled; @@ -373,7 +374,7 @@ export function getDeepLinks( if ( deepLink.id === SecurityPageName.case && capabilities != null && - capabilities.siem.crud_cases === false + capabilities[CASES_FEATURE_ID].crud_cases === false ) { return { ...deepLink, diff --git a/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts b/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts index adc06468d9a02..fdaed64ba91d7 100644 --- a/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts +++ b/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts @@ -12,7 +12,12 @@ import { i18n } from '@kbn/i18n'; import { camelCase, isArray, isObject } from 'lodash'; import { set } from '@elastic/safer-lodash-set'; -import { APP_ID, DEFAULT_DATE_FORMAT, DEFAULT_DATE_FORMAT_TZ } from '../../../../common/constants'; +import { + APP_ID, + CASES_FEATURE_ID, + DEFAULT_DATE_FORMAT, + DEFAULT_DATE_FORMAT_TZ, +} from '../../../../common/constants'; import { errorToToaster, useStateToaster } from '../../components/toasters'; import { AuthenticatedUser } from '../../../../../security/common/model'; import { NavigateToAppOptions } from '../../../../../../../src/core/public'; @@ -151,13 +156,9 @@ export const useGetUserCasesPermissions = () => { const uiCapabilities = useKibana().services.application.capabilities; useEffect(() => { - const capabilitiesCanUserCRUD: boolean = - typeof uiCapabilities.siem.crud_cases === 'boolean' ? uiCapabilities.siem.crud_cases : false; - const capabilitiesCanUserRead: boolean = - typeof uiCapabilities.siem.read_cases === 'boolean' ? uiCapabilities.siem.read_cases : false; setCasesPermissions({ - crud: capabilitiesCanUserCRUD, - read: capabilitiesCanUserRead, + crud: !!uiCapabilities[CASES_FEATURE_ID].crud_cases, + read: !!uiCapabilities[CASES_FEATURE_ID].read_cases, }); }, [uiCapabilities]); diff --git a/x-pack/plugins/security_solution/server/features.ts b/x-pack/plugins/security_solution/server/features.ts index cff1e2482a1ee..185bf43a3da37 100644 --- a/x-pack/plugins/security_solution/server/features.ts +++ b/x-pack/plugins/security_solution/server/features.ts @@ -9,49 +9,48 @@ import { i18n } from '@kbn/i18n'; import { KibanaFeatureConfig, SubFeatureConfig } from '../../features/common'; import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server'; -import { APP_ID, SERVER_APP_ID } from '../common/constants'; +import { APP_ID, CASES_FEATURE_ID, SERVER_APP_ID } from '../common/constants'; import { savedObjectTypes } from './saved_objects'; -const CASES_SUB_FEATURE: SubFeatureConfig = { - name: 'Cases', - privilegeGroups: [ - { - groupType: 'mutually_exclusive', - privileges: [ - { - id: 'cases_all', - includeIn: 'all', - name: 'All', - savedObject: { - all: [], - read: [], - }, - // using variables with underscores here otherwise when we retrieve them from the kibana - // capabilities in a hook I get type errors regarding boolean | ReadOnly<{[x: string]: boolean}> - ui: ['crud_cases', 'read_cases'], // uiCapabilities.siem.crud_cases - cases: { - all: [APP_ID], - }, - }, - { - id: 'cases_read', - includeIn: 'read', - name: 'Read', - savedObject: { - all: [], - read: [], - }, - // using variables with underscores here otherwise when we retrieve them from the kibana - // capabilities in a hook I get type errors regarding boolean | ReadOnly<{[x: string]: boolean}> - ui: ['read_cases'], // uiCapabilities.siem.read_cases - cases: { - read: [APP_ID], - }, - }, - ], +export const getCasesKibanaFeature = (): KibanaFeatureConfig => ({ + id: CASES_FEATURE_ID, + name: i18n.translate('xpack.securitySolution.featureRegistry.linkSecuritySolutionCaseTitle', { + defaultMessage: 'Cases', + }), + order: 1100, + category: DEFAULT_APP_CATEGORIES.security, + app: [CASES_FEATURE_ID, 'kibana'], + catalogue: [APP_ID], + cases: [APP_ID], + privileges: { + all: { + app: [CASES_FEATURE_ID, 'kibana'], + catalogue: [APP_ID], + cases: { + all: [APP_ID], + }, + api: [], + savedObject: { + all: [], + read: [], + }, + ui: ['crud_cases', 'read_cases'], // uiCapabilities[CASES_FEATURE_ID].crud_cases or read_cases }, - ], -}; + read: { + app: [CASES_FEATURE_ID, 'kibana'], + catalogue: [APP_ID], + cases: { + read: [APP_ID], + }, + api: [], + savedObject: { + all: [], + read: [], + }, + ui: ['read_cases'], // uiCapabilities[CASES_FEATURE_ID].read_cases + }, + }, +}); export const getAlertsSubFeature = (ruleTypes: string[]): SubFeatureConfig => ({ name: i18n.translate('xpack.securitySolution.featureRegistry.manageAlertsName', { @@ -108,18 +107,17 @@ export const getKibanaPrivilegesFeaturePrivileges = (ruleTypes: string[]): Kiban order: 1100, category: DEFAULT_APP_CATEGORIES.security, app: [APP_ID, 'kibana'], - catalogue: ['securitySolution'], + catalogue: [APP_ID], management: { insightsAndAlerting: ['triggersActions'], }, alerting: ruleTypes, - cases: [APP_ID], - subFeatures: [{ ...CASES_SUB_FEATURE } /* , { ...getAlertsSubFeature(ruleTypes) } */], + subFeatures: [], privileges: { all: { app: [APP_ID, 'kibana'], - catalogue: ['securitySolution'], - api: ['securitySolution', 'lists-all', 'lists-read', 'rac'], + catalogue: [APP_ID], + api: [APP_ID, 'lists-all', 'lists-read', 'rac'], savedObject: { all: ['alert', 'exception-list', 'exception-list-agnostic', ...savedObjectTypes], read: [], @@ -136,8 +134,8 @@ export const getKibanaPrivilegesFeaturePrivileges = (ruleTypes: string[]): Kiban }, read: { app: [APP_ID, 'kibana'], - catalogue: ['securitySolution'], - api: ['securitySolution', 'lists-read', 'rac'], + catalogue: [APP_ID], + api: [APP_ID, 'lists-read', 'rac'], savedObject: { all: [], read: ['exception-list', 'exception-list-agnostic', ...savedObjectTypes], diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json index ef3a3bef324f9..7d81897708422 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/detections_admin/detections_role.json @@ -33,6 +33,7 @@ "feature": { "ml": ["all"], "siem": ["all", "read_alerts", "crud_alerts"], + "securitySolutionCases": ["all"], "actions": ["read"], "builtInAlerts": ["all"], "dev_tools": ["all"] diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json index f9d2c68e6878a..34d8b7b4d4446 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/hunter/detections_role.json @@ -38,6 +38,7 @@ "feature": { "ml": ["read"], "siem": ["all", "read_alerts", "crud_alerts"], + "securitySolutionCases": ["all"], "actions": ["read"], "builtInAlerts": ["all"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json index 5c6188b053d20..f6b31d4b3ed81 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/platform_engineer/detections_role.json @@ -33,6 +33,7 @@ "feature": { "ml": ["all"], "siem": ["all", "read_alerts", "crud_alerts"], + "securitySolutionCases": ["all"], "actions": ["all"], "builtInAlerts": ["all"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json index d04251542d11b..4cfc6a3ec80ed 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/reader/detections_role.json @@ -26,6 +26,7 @@ "feature": { "ml": ["read"], "siem": ["read", "read_alerts"], + "securitySolutionCases": ["read"], "actions": ["read"], "builtInAlerts": ["read"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json index f7b8818d6c004..a23aec6d6e403 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/rule_author/detections_role.json @@ -36,6 +36,7 @@ "feature": { "ml": ["read"], "siem": ["all", "read_alerts", "crud_alerts"], + "securitySolutionCases": ["all"], "actions": ["read"], "builtInAlerts": ["all"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json index 324fb2737f24f..da855c6926438 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/soc_manager/detections_role.json @@ -36,6 +36,7 @@ "feature": { "ml": ["read"], "siem": ["all", "read_alerts", "crud_alerts"], + "securitySolutionCases": ["all"], "actions": ["all"], "builtInAlerts": ["all"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json index 90232bdb53fed..a63d0186a2a91 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t1_analyst/detections_role.json @@ -26,6 +26,7 @@ "feature": { "ml": ["read"], "siem": ["read", "read_alerts"], + "securitySolutionCases": ["read"], "actions": ["read"], "builtInAlerts": ["read"] }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json index 9885ba0ee610b..de1ff5af99c1b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/scripts/roles_users/t2_analyst/detections_role.json @@ -28,6 +28,7 @@ "feature": { "ml": ["read"], "siem": ["read", "read_alerts"], + "securitySolutionCases": ["read"], "actions": ["read"], "builtInAlerts": ["read"] }, diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index 59bf5057f2796..391beb3c40121 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -100,7 +100,7 @@ import aadFieldConversion from './lib/detection_engine/routes/index/signal_aad_m import { alertsFieldMap } from './lib/detection_engine/rule_types/field_maps/alerts'; import { rulesFieldMap } from './lib/detection_engine/rule_types/field_maps/rules'; import { RuleExecutionLogClient } from './lib/detection_engine/rule_execution_log/rule_execution_log_client'; -import { getKibanaPrivilegesFeaturePrivileges } from './features'; +import { getKibanaPrivilegesFeaturePrivileges, getCasesKibanaFeature } from './features'; import { EndpointMetadataService } from './endpoint/services/metadata'; import { CreateRuleOptions } from './lib/detection_engine/rule_types/types'; import { ctiFieldMap } from './lib/detection_engine/rule_types/field_maps/cti'; @@ -305,6 +305,7 @@ export class Plugin implements IPlugin