From 01b8482cd9b383ccedc4deec6495eb003d37a64e Mon Sep 17 00:00:00 2001 From: Garrett Spong Date: Mon, 20 Jun 2022 04:39:03 -0600 Subject: [PATCH] [Security Solution][Detections] Updates Get Installed Integrations route to use Internal SO Client (#134373) ## Summary Follow up to https://github.com/elastic/kibana/pull/134299 that updates the `Get Installed Integrations` route to use the Internal SO Client and removes client-side privilege checks. This change ensures the `Related Integrations` feature works regardless of client users Fleet/Integration/SOM privileges, enabling all Security Solution users the ability to see which integrations are installed/configured with relation to their Detection Rules. This change is helpful for low privilege users like T1/T2 Analysts that may not have more broad privileges like SOM or Fleet to still see which of their Detection Rules have the necessary integrations. ### Test instructions To test, configure a role with the 3 mentioned privileges (SOM/Integrations/Fleet) as `None`, e.g.

Then the UI should _still show_ installed details (installed/not installed badges): ##### Rules Table

##### Rules Details

### Checklist Delete any items that are not applicable to this PR. - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials * Working docs as part of https://github.com/elastic/security-docs/issues/2015 - [X] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### Risk Ma --- .../related_integrations/integration_details.test.ts | 12 +----------- .../related_integrations/integration_details.ts | 12 +++--------- .../integrations_popover/index.tsx | 6 +++--- .../use_integration_privileges.ts | 6 ++++++ .../related_integrations/use_related_integrations.ts | 8 +------- .../get_installed_integrations_route.ts | 3 +-- 6 files changed, 15 insertions(+), 32 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.test.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.test.ts index 58ad887013468..54f6f9e1d24f8 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.test.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.test.ts @@ -6,16 +6,11 @@ */ import { calculateIntegrationDetails } from './integration_details'; -import { IntegrationPrivileges } from './integration_privileges'; describe('Integration Details', () => { describe('calculateIntegrationDetails', () => { - const stubPrivileges: IntegrationPrivileges = { - canReadInstalledIntegrations: true, - }; - test('it returns a the correct integrationDetails', () => { - const integrationDetails = calculateIntegrationDetails(stubPrivileges, [], []); + const integrationDetails = calculateIntegrationDetails([], []); expect(integrationDetails.length).toEqual(0); }); @@ -23,7 +18,6 @@ describe('Integration Details', () => { describe('version is correctly computed', () => { test('Unknown integration that does not exist', () => { const integrationDetails = calculateIntegrationDetails( - stubPrivileges, [ { package: 'foo1', @@ -48,7 +42,6 @@ describe('Integration Details', () => { test('Integration that is not installed', () => { const integrationDetails = calculateIntegrationDetails( - stubPrivileges, [ { package: 'aws', @@ -69,7 +62,6 @@ describe('Integration Details', () => { test('Integration that is installed, and its version matches required version', () => { const integrationDetails = calculateIntegrationDetails( - stubPrivileges, [ { package: 'aws', @@ -114,7 +106,6 @@ describe('Integration Details', () => { test('Integration that is installed, and its version is less than required version', () => { const integrationDetails = calculateIntegrationDetails( - stubPrivileges, [ { package: 'aws', @@ -150,7 +141,6 @@ describe('Integration Details', () => { test('Integration that is installed, and its version is greater than required version', () => { const integrationDetails = calculateIntegrationDetails( - stubPrivileges, [ { package: 'aws', diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts index 177a7921baf55..a4e2dc83084ab 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integration_details.ts @@ -13,7 +13,6 @@ import { RelatedIntegration, RelatedIntegrationArray, } from '../../../../../common/detection_engine/schemas/common'; -import { IntegrationPrivileges } from './integration_privileges'; export interface IntegrationDetails { packageName: string; @@ -45,13 +44,12 @@ export interface UnknownInstallationStatus { * has. */ export const calculateIntegrationDetails = ( - privileges: IntegrationPrivileges, relatedIntegrations: RelatedIntegrationArray, installedIntegrations: InstalledIntegrationArray | undefined ): IntegrationDetails[] => { const integrationMatches = findIntegrationMatches(relatedIntegrations, installedIntegrations); const integrationDetails = integrationMatches.map((integration) => { - return createIntegrationDetails(integration, privileges); + return createIntegrationDetails(integration); }); return integrationDetails.sort((a, b) => { @@ -90,19 +88,15 @@ const findIntegrationMatches = ( }); }; -const createIntegrationDetails = ( - integration: IntegrationMatch, - privileges: IntegrationPrivileges -): IntegrationDetails => { +const createIntegrationDetails = (integration: IntegrationMatch): IntegrationDetails => { const { related, installed, isLoaded } = integration; - const { canReadInstalledIntegrations } = privileges; const packageName = related.package; const integrationName = related.integration ?? null; const requiredVersion = related.version; // We don't know whether the integration is installed or not. - if (!canReadInstalledIntegrations || !isLoaded) { + if (!isLoaded) { const integrationTitle = getCapitalizedTitle(packageName, integrationName); const targetVersion = getMinimumConcreteVersionMatchingSemver(requiredVersion); const targetUrl = buildTargetUrl(packageName, integrationName, targetVersion); diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx index 0416bfa219859..6c17b182381ca 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/integrations_popover/index.tsx @@ -53,7 +53,7 @@ const IntegrationListItem = styled('li')` */ const IntegrationsPopoverComponent = ({ relatedIntegrations }: IntegrationsPopoverProps) => { const [isPopoverOpen, setPopoverOpen] = useState(false); - const { integrations, privileges, isLoaded } = useRelatedIntegrations(relatedIntegrations); + const { integrations, isLoaded } = useRelatedIntegrations(relatedIntegrations); const enabledIntegrations = useMemo(() => { return integrations.filter( @@ -65,10 +65,10 @@ const IntegrationsPopoverComponent = ({ relatedIntegrations }: IntegrationsPopov const numIntegrationsEnabled = enabledIntegrations.length; const badgeTitle = useMemo(() => { - return privileges.canReadInstalledIntegrations && isLoaded + return isLoaded ? `${numIntegrationsEnabled}/${numIntegrations} ${i18n.INTEGRATIONS_BADGE}` : `${numIntegrations} ${i18n.INTEGRATIONS_BADGE}`; - }, [privileges, isLoaded, numIntegrations, numIntegrationsEnabled]); + }, [isLoaded, numIntegrations, numIntegrationsEnabled]); return ( { const services = useKibana().services; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts index 4f1d467420774..294a084aaeb80 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_related_integrations.ts @@ -9,33 +9,27 @@ import { useMemo } from 'react'; import { RelatedIntegrationArray } from '../../../../../common/detection_engine/schemas/common'; import { calculateIntegrationDetails, IntegrationDetails } from './integration_details'; -import { IntegrationPrivileges } from './integration_privileges'; -import { useIntegrationPrivileges } from './use_integration_privileges'; import { useInstalledIntegrations } from './use_installed_integrations'; export interface UseRelatedIntegrationsResult { integrations: IntegrationDetails[]; - privileges: IntegrationPrivileges; isLoaded: boolean; } export const useRelatedIntegrations = ( relatedIntegrations: RelatedIntegrationArray ): UseRelatedIntegrationsResult => { - const privileges = useIntegrationPrivileges(); const { data: installedIntegrations } = useInstalledIntegrations({ packages: [] }); return useMemo(() => { const integrationDetails = calculateIntegrationDetails( - privileges, relatedIntegrations, installedIntegrations ); return { integrations: integrationDetails, - privileges, isLoaded: installedIntegrations != null, }; - }, [privileges, relatedIntegrations, installedIntegrations]); + }, [relatedIntegrations, installedIntegrations]); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts index 3682949bd652d..5809af1b1642f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/fleet/get_installed_integrations/get_installed_integrations_route.ts @@ -31,10 +31,9 @@ export const getInstalledIntegrationsRoute = (router: SecuritySolutionPluginRout try { const ctx = await context.resolve(['core', 'securitySolution']); const fleet = ctx.securitySolution.getInternalFleetServices(); - const soClient = ctx.core.savedObjects.client; const set = createInstalledIntegrationSet(); - const packagePolicies = await fleet.packagePolicy.list(soClient, {}); + const packagePolicies = await fleet.packagePolicy.list(fleet.internalReadonlySoClient, {}); packagePolicies.items.forEach((policy) => { set.addPackagePolicy(policy);