mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Security Solution] Allow only users with 'all' privileges to install and upgrade prebuilt rules (#161454)
Fixes: https://github.com/elastic/kibana/issues/161443 ## Summary ### When user doesn't have write permission: - Disables "Add Elastic rules" button and removes Rule Updates tab  - Disables buttons to individually install rules, install selected rules and install all rules  - Disables buttons to individually upgrade rules, upgrade selected rules and upgrade all rules  ### `_perform` endpoints - Returns 403 when installing all rules or specific rules   - Returns 403 when upgrading all rules or specific rules   ### Checklist Delete any items that are not applicable to this PR. - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) ### For maintainers - [ ] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) --------- Co-authored-by: Dmitrii <dmitrii.shevchenko@elastic.co>
This commit is contained in:
parent
4baeafe4e6
commit
31b28a0660
8 changed files with 38 additions and 24 deletions
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { useUserData } from '../../../../../detections/components/user_info';
|
||||
import { useAddPrebuiltRulesTableContext } from './add_prebuilt_rules_table_context';
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -15,6 +16,8 @@ export const AddPrebuiltRulesHeaderButtons = () => {
|
|||
state: { rules, selectedRules, loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { installAllRules, installSelectedRules },
|
||||
} = useAddPrebuiltRulesTableContext();
|
||||
const [{ loading: isUserDataLoading, canUserCRUD }] = useUserData();
|
||||
const canUserEditRules = canUserCRUD && !isUserDataLoading;
|
||||
|
||||
const isRulesAvailableForInstall = rules.length > 0;
|
||||
const numberOfSelectedRules = selectedRules.length ?? 0;
|
||||
|
@ -29,7 +32,7 @@ export const AddPrebuiltRulesHeaderButtons = () => {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={installSelectedRules}
|
||||
disabled={isRequestInProgress}
|
||||
disabled={!canUserEditRules || isRequestInProgress}
|
||||
data-test-subj="installSelectedRulesButton"
|
||||
>
|
||||
{i18n.INSTALL_SELECTED_RULES(numberOfSelectedRules)}
|
||||
|
@ -43,7 +46,7 @@ export const AddPrebuiltRulesHeaderButtons = () => {
|
|||
iconType="plusInCircle"
|
||||
data-test-subj="installAllRulesButton"
|
||||
onClick={installAllRules}
|
||||
disabled={!isRulesAvailableForInstall || isRequestInProgress}
|
||||
disabled={!canUserEditRules || !isRulesAvailableForInstall || isRequestInProgress}
|
||||
>
|
||||
{i18n.INSTALL_ALL}
|
||||
{isRuleInstalling ? <EuiLoadingSpinner size="s" /> : undefined}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { useUserData } from '../../../../detections/components/user_info';
|
||||
import { TabNavigation } from '../../../../common/components/navigation/tab_navigation';
|
||||
import { usePrebuiltRulesStatus } from '../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_status';
|
||||
import { useRuleManagementFilters } from '../../../rule_management/logic/use_rule_management_filters';
|
||||
|
@ -21,26 +22,14 @@ export const RulesTableToolbar = React.memo(() => {
|
|||
const { data: ruleManagementFilters } = useRuleManagementFilters();
|
||||
const { data: prebuiltRulesStatus } = usePrebuiltRulesStatus();
|
||||
|
||||
const [{ loading, canUserCRUD }] = useUserData();
|
||||
|
||||
const installedTotal =
|
||||
(ruleManagementFilters?.rules_summary.custom_count ?? 0) +
|
||||
(ruleManagementFilters?.rules_summary.prebuilt_installed_count ?? 0);
|
||||
const updateTotal = prebuiltRulesStatus?.num_prebuilt_rules_to_upgrade ?? 0;
|
||||
|
||||
const ruleUpdateTab = useMemo(
|
||||
() => ({
|
||||
[AllRulesTabs.updates]: {
|
||||
id: AllRulesTabs.updates,
|
||||
name: i18n.RULE_UPDATES_TAB,
|
||||
disabled: false,
|
||||
href: `/rules/${AllRulesTabs.updates}`,
|
||||
isBeta: updateTotal > 0,
|
||||
betaOptions: {
|
||||
text: `${updateTotal}`,
|
||||
},
|
||||
},
|
||||
}),
|
||||
[updateTotal]
|
||||
);
|
||||
const shouldDisplayRuleUpdatesTab = !loading && canUserCRUD && updateTotal > 0;
|
||||
|
||||
const ruleTabs = useMemo(
|
||||
() => ({
|
||||
|
@ -64,9 +53,22 @@ export const RulesTableToolbar = React.memo(() => {
|
|||
text: `${installedTotal}`,
|
||||
},
|
||||
},
|
||||
...(updateTotal > 0 ? ruleUpdateTab : {}),
|
||||
...(shouldDisplayRuleUpdatesTab
|
||||
? {
|
||||
[AllRulesTabs.updates]: {
|
||||
id: AllRulesTabs.updates,
|
||||
name: i18n.RULE_UPDATES_TAB,
|
||||
disabled: false,
|
||||
href: `/rules/${AllRulesTabs.updates}`,
|
||||
isBeta: updateTotal > 0,
|
||||
betaOptions: {
|
||||
text: `${updateTotal}`,
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
}),
|
||||
[installedTotal, ruleUpdateTab, updateTotal]
|
||||
[installedTotal, updateTotal, shouldDisplayRuleUpdatesTab]
|
||||
);
|
||||
|
||||
return <TabNavigation navTabs={ruleTabs} />;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { useUserData } from '../../../../../detections/components/user_info';
|
||||
import * as i18n from './translations';
|
||||
import { useUpgradePrebuiltRulesTableContext } from './upgrade_prebuilt_rules_table_context';
|
||||
|
||||
|
@ -15,6 +16,8 @@ export const UpgradePrebuiltRulesTableButtons = () => {
|
|||
state: { rules, selectedRules, loadingRules, isRefetching, isUpgradingSecurityPackages },
|
||||
actions: { upgradeAllRules, upgradeSelectedRules },
|
||||
} = useUpgradePrebuiltRulesTableContext();
|
||||
const [{ loading: isUserDataLoading, canUserCRUD }] = useUserData();
|
||||
const canUserEditRules = canUserCRUD && !isUserDataLoading;
|
||||
|
||||
const isRulesAvailableForUpgrade = rules.length > 0;
|
||||
const numberOfSelectedRules = selectedRules.length ?? 0;
|
||||
|
@ -29,7 +32,7 @@ export const UpgradePrebuiltRulesTableButtons = () => {
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
onClick={upgradeSelectedRules}
|
||||
disabled={isRequestInProgress}
|
||||
disabled={!canUserEditRules || isRequestInProgress}
|
||||
data-test-subj="upgradeSelectedRulesButton"
|
||||
>
|
||||
<>
|
||||
|
@ -44,7 +47,7 @@ export const UpgradePrebuiltRulesTableButtons = () => {
|
|||
fill
|
||||
iconType="plusInCircle"
|
||||
onClick={upgradeAllRules}
|
||||
disabled={!isRulesAvailableForUpgrade || isRequestInProgress}
|
||||
disabled={!canUserEditRules || !isRulesAvailableForUpgrade || isRequestInProgress}
|
||||
data-test-subj="upgradeAllRulesButton"
|
||||
>
|
||||
{i18n.UPDATE_ALL}
|
||||
|
|
|
@ -107,7 +107,7 @@ const RulesPageComponent: React.FC = () => {
|
|||
<SuperHeader>
|
||||
<EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<AddElasticRulesButton />
|
||||
<AddElasticRulesButton isDisabled={!canUserCRUD || loading} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiToolTip position="top" content={i18n.UPLOAD_VALUE_LISTS_TOOLTIP}>
|
||||
|
|
|
@ -17,12 +17,14 @@ import { usePrebuiltRulesStatus } from '../../../../detection_engine/rule_manage
|
|||
interface AddElasticRulesButtonProps {
|
||||
'data-test-subj'?: string;
|
||||
fill?: boolean;
|
||||
isDisabled: boolean;
|
||||
showBadge?: boolean;
|
||||
}
|
||||
|
||||
export const AddElasticRulesButton = ({
|
||||
'data-test-subj': dataTestSubj = 'addElasticRulesButton',
|
||||
fill,
|
||||
isDisabled,
|
||||
showBadge = true,
|
||||
}: AddElasticRulesButtonProps) => {
|
||||
const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps();
|
||||
|
@ -43,6 +45,7 @@ export const AddElasticRulesButton = ({
|
|||
color={'primary'}
|
||||
onClick={onClickLink}
|
||||
data-test-subj={dataTestSubj}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
{i18n.ADD_ELASTIC_RULES}
|
||||
{newRulesCount > 0 && showBadge && (
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import React, { memo } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { useUserData } from '../../user_info';
|
||||
import { AddElasticRulesButton } from './add_elastic_rules_button';
|
||||
import * as i18n from './translations';
|
||||
|
||||
|
@ -18,6 +19,7 @@ const EmptyPrompt = styled(EuiEmptyPrompt)`
|
|||
EmptyPrompt.displayName = 'EmptyPrompt';
|
||||
|
||||
const PrePackagedRulesPromptComponent = () => {
|
||||
const [{ loading, canUserCRUD }] = useUserData();
|
||||
return (
|
||||
<EmptyPrompt
|
||||
data-test-subj="rulesEmptyPrompt"
|
||||
|
@ -27,6 +29,7 @@ const PrePackagedRulesPromptComponent = () => {
|
|||
<EuiFlexGroup justifyContent="center">
|
||||
<EuiFlexItem grow={false}>
|
||||
<AddElasticRulesButton
|
||||
isDisabled={!canUserCRUD || loading}
|
||||
fill={true}
|
||||
data-test-subj="add-elastc-rules-empty-empty-prompt-button"
|
||||
showBadge={false}
|
||||
|
|
|
@ -35,7 +35,7 @@ export const performRuleInstallationRoute = (router: SecuritySolutionPluginRoute
|
|||
body: buildRouteValidation(PerformRuleInstallationRequestBody),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:securitySolution'],
|
||||
tags: ['access:securitySolution-all'],
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
|
|
|
@ -39,7 +39,7 @@ export const performRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) =>
|
|||
body: buildRouteValidation(PerformRuleUpgradeRequestBody),
|
||||
},
|
||||
options: {
|
||||
tags: ['access:securitySolution'],
|
||||
tags: ['access:securitySolution-all'],
|
||||
},
|
||||
},
|
||||
async (context, request, response) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue