Skip to content

Commit

Permalink
[Security Solution] Fix the feature app list (elastic#191965)
Browse files Browse the repository at this point in the history
## Summary

Fixes elastic/kibana-team#1136

The Kibana feature definition for Security Solution was missing the
correct plugin ID registered in the `app` definition. We were still
defining the old _"securitySolution"_ app ID in the `app` property,
instead of the new _"securitySolutionUI"_ ID.

The Security Solution plugin ID change (_"securitySolution"_ ->
_"securitySolutionUI"_) was done a long time ago, the inconsistency with
the Security feature definition is causing the _Security_ app to still
be visible in the global search when the Security feature is disabled:

- In the role features
<img width="737" alt="Security and Cases disabled"
src="https://github.com/user-attachments/assets/146b8205-90f7-4218-9f1a-7b55c3bad563">

- Or in the space features config
<img width="1213" alt="Captura de pantalla 2024-09-03 a les 15 31 09"
src="https://github.com/user-attachments/assets/2563675a-d956-4422-a887-d6d95bcad773">


This is fixed now:

Before:
<img width="1302" alt="Security app incorrectly enabled"
src="https://github.com/user-attachments/assets/8031f054-7cfb-4098-93c2-eac402501887">

After:
<img width="1302" alt="Security app disabled properly"
src="https://github.com/user-attachments/assets/a4f38ec2-fb78-4b1b-8c2d-bac58b97ff99">


### Caveat

As per this PR changes: elastic#113573
In the Kibana features of the role, under the Security catalog, both
Security and Cases features need to be `none` for the Security Solution
plugin to be disabled. Otherwise, we must enable the plugin and make the
enabled features available. So, with a role with the following Kibana
features:

<img width="737" alt="Security disabled cases enabled"
src="https://github.com/user-attachments/assets/aca8288e-9dd9-49d0-b864-e60273d30759">

The Security app needs to be available and display only Cases available:

<img width="247" alt="navigation with only cases"
src="https://github.com/user-attachments/assets/d4866edb-1d1d-4290-a399-76a37536b05c">

---------

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
semd and elasticmachine authored Oct 1, 2024
1 parent bdd57b6 commit e373e44
Showing 1 changed file with 106 additions and 89 deletions.
195 changes: 106 additions & 89 deletions x-pack/plugins/security_solution/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
PluginInitializerContext,
Plugin as IPlugin,
} from '@kbn/core/public';
import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { AppStatus, DEFAULT_APP_CATEGORIES } from '@kbn/core/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public';
import { uiMetricService } from '@kbn/cloud-security-posture-common/utils/ui_metrics';
Expand Down Expand Up @@ -208,88 +208,20 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S

public start(core: CoreStart, plugins: StartPlugins): PluginStart {
this.services.start(core, plugins);

if (plugins.fleet) {
const { registerExtension } = plugins.fleet;
const registerOptions: FleetUiExtensionGetterOptions = {
coreStart: core,
depsStart: plugins,
services: {
upsellingService: this.contract.upsellingService,
},
};

registerExtension({
package: 'endpoint',
view: 'package-policy-edit',
Component: getLazyEndpointPolicyEditExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-response',
Component: getLazyEndpointPolicyResponseExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-generic-errors-list',
Component: getLazyEndpointGenericErrorsListExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create',
Component: getLazyEndpointPolicyCreateExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create-multi-step',
Component: LazyEndpointPolicyCreateMultiStepExtension,
});

registerExtension({
package: 'endpoint',
view: 'package-detail-custom',
Component: getLazyEndpointPackageCustomExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-detail-assets',
Component: LazyEndpointCustomAssetsExtension,
});

registerExtension({
package: 'endpoint',
view: 'endpoint-agent-tamper-protection',
Component: getLazyEndpointAgentTamperProtectionExtension(registerOptions),
});

registerExtension({
package: 'cloud_security_posture',
view: 'pli-auth-block',
Component: getLazyCloudSecurityPosturePliAuthBlockExtension(registerOptions),
});

registerExtension({
package: 'cribl',
view: 'package-policy-replace-define-step',
Component: LazyCustomCriblExtension,
});
}

// Not using await to prevent blocking start execution
this.registerAppLinks(core, plugins);

this.registerFleetExtensions(core, plugins);
this.registerPluginUpdates(core, plugins); // Not awaiting to prevent blocking start execution
return this.contract.getStartContract(core);
}

public stop() {
this.services.stop();
}

/**
* SubPlugins are the individual building blocks of the Security Solution plugin.
* They are lazily instantiated to improve startup time.
* TODO: Move these functions to ./lazy_sub_plugins.ts
*/
private async createSubPlugins(): Promise<SubPlugins> {
if (!this._subPlugins) {
const { subPluginClasses } = await this.lazySubPlugins();
Expand Down Expand Up @@ -317,9 +249,6 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
return this._subPlugins;
}

/**
* All started subPlugins.
*/
private async startSubPlugins(
storage: Storage,
core: CoreStart,
Expand Down Expand Up @@ -389,7 +318,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
}

/**
* Registers the alerts tables configurations.
* Registers the alerts tables configurations to the triggersActionsUi plugin.
*/
private async registerAlertsTableConfiguration(
triggersActionsUi: TriggersAndActionsUIPublicPluginSetup
Expand All @@ -406,38 +335,126 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S
}

/**
* Registers deepLinks and appUpdater for appLinks using license.
* Registers the plugin updates including status, visibleIn, and deepLinks via the plugin updater$.
*/
async registerAppLinks(core: CoreStart, plugins: StartPlugins) {
private async registerPluginUpdates(core: CoreStart, plugins: StartPlugins) {
const { license$ } = plugins.licensing;
const { capabilities } = core.application;
const { upsellingService, isSolutionNavigationEnabled$ } = this.contract;

// When the user does not have access to SIEM (main Security feature) nor Security Cases feature, the plugin must be inaccessible.
if (!capabilities.siem?.show && !capabilities.securitySolutionCases?.read_cases) {
this.appUpdater$.next(() => ({
status: AppStatus.inaccessible,
visibleIn: [],
}));
// no need to register the links updater when the plugin is inaccessible
return;
}

// Configuration of AppLinks updater registration based on license and capabilities
const {
appLinks: initialAppLinks,
getFilteredLinks,
solutionAppLinksSwitcher,
} = await this.lazyApplicationLinks();
const { license$ } = plugins.licensing;
const { upsellingService, isSolutionNavigationEnabled$ } = this.contract;

registerDeepLinksUpdater(this.appUpdater$, isSolutionNavigationEnabled$);

const appLinks$ = new Subject<AppLinkItems>();
appLinks$.next(initialAppLinks);
const appLinksToUpdate$ = new Subject<AppLinkItems>();
appLinksToUpdate$.next(initialAppLinks);

appLinks$
appLinksToUpdate$
.pipe(combineLatestWith(license$, isSolutionNavigationEnabled$))
.subscribe(([appLinks, license, isSolutionNavigationEnabled]) => {
const links = isSolutionNavigationEnabled ? solutionAppLinksSwitcher(appLinks) : appLinks;
const linksPermissions: LinksPermissions = {
experimentalFeatures: this.experimentalFeatures,
upselling: upsellingService,
capabilities: core.application.capabilities,
capabilities,
uiSettingsClient: core.uiSettings,
...(license.type != null && { license }),
};
updateAppLinks(links, linksPermissions);
});

const filteredLinks = await getFilteredLinks(core, plugins);
appLinks$.next(filteredLinks);
appLinksToUpdate$.next(filteredLinks);
}

private registerFleetExtensions(core: CoreStart, plugins: StartPlugins) {
if (!plugins.fleet) {
return;
}

const { registerExtension } = plugins.fleet;
const registerOptions: FleetUiExtensionGetterOptions = {
coreStart: core,
depsStart: plugins,
services: {
upsellingService: this.contract.upsellingService,
},
};

registerExtension({
package: 'endpoint',
view: 'package-policy-edit',
Component: getLazyEndpointPolicyEditExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-response',
Component: getLazyEndpointPolicyResponseExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-generic-errors-list',
Component: getLazyEndpointGenericErrorsListExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create',
Component: getLazyEndpointPolicyCreateExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-policy-create-multi-step',
Component: LazyEndpointPolicyCreateMultiStepExtension,
});

registerExtension({
package: 'endpoint',
view: 'package-detail-custom',
Component: getLazyEndpointPackageCustomExtension(registerOptions),
});

registerExtension({
package: 'endpoint',
view: 'package-detail-assets',
Component: LazyEndpointCustomAssetsExtension,
});

registerExtension({
package: 'endpoint',
view: 'endpoint-agent-tamper-protection',
Component: getLazyEndpointAgentTamperProtectionExtension(registerOptions),
});

registerExtension({
package: 'cloud_security_posture',
view: 'pli-auth-block',
Component: getLazyCloudSecurityPosturePliAuthBlockExtension(registerOptions),
});

registerExtension({
package: 'cribl',
view: 'package-policy-replace-define-step',
Component: LazyCustomCriblExtension,
});
}

// Lazy loaded dependencies
Expand Down

0 comments on commit e373e44

Please sign in to comment.