Skip to content

Commit

Permalink
[Fleet] Disable selecting standalone instructions for user without ag…
Browse files Browse the repository at this point in the history
…ent policies READ permissions (elastic#187517)
  • Loading branch information
nchaulet committed Jul 4, 2024
1 parent 8bdee42 commit c27ca40
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
3 changes: 1 addition & 2 deletions x-pack/plugins/fleet/common/authz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,7 @@ export const calculateAuthz = ({
// These are currently used by Fleet Server setup
setup: fleet.all || fleet.setup,
readEnrollmentTokens: (fleet.all || fleet.setup || fleet.agents?.all) ?? false,
readAgentPolicies:
(fleet.all || fleet.read || fleet.setup || fleet.agentPolicies?.read) ?? false,
readAgentPolicies: (fleet.all || fleet.setup) ?? false,
};

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import type { RenderResult } from '@testing-library/react';
import { createFleetTestRendererMock } from '../../mock';
import type { AgentPolicy } from '../../../common';
import { sendGetOneAgentPolicy } from '../../hooks/use_request';
import { useAgentEnrollmentFlyoutData, useFleetServerStandalone } from '../../hooks';
import { useAgentEnrollmentFlyoutData, useAuthz, useFleetServerStandalone } from '../../hooks';

import { useAdvancedForm } from '../../applications/fleet/components/fleet_server_instructions/hooks';
import { useFleetServerUnhealthy } from '../../applications/fleet/sections/agents/hooks/use_fleet_server_unhealthy';

import type { FlyOutProps } from './types';
import { AgentEnrollmentFlyout } from '.';

jest.mock('../../hooks/use_authz');

const render = (props?: Partial<FlyOutProps>) => {
cleanup();
const renderer = createFleetTestRendererMock();
Expand All @@ -47,6 +49,11 @@ describe('<AgentEnrollmentFlyout />', () => {
let results: RenderResult;

beforeEach(async () => {
jest.mocked(useAuthz).mockReturnValue({
fleet: {
readAgentPolicies: true,
},
} as any);
jest.mocked(useFleetServerStandalone).mockReturnValue({ isFleetServerStandalone: false });

(useFleetServerUnhealthy as jest.Mock).mockReturnValue({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
useFleetStatus,
useAgentEnrollmentFlyoutData,
useFleetServerHostsForPolicy,
useAuthz,
} from '../../hooks';
import { FLEET_SERVER_PACKAGE, MAX_FLYOUT_WIDTH } from '../../constants';
import type { PackagePolicy, AgentPolicy } from '../../types';
Expand Down Expand Up @@ -61,6 +62,8 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<FlyOutProps> = ({
return policies.find((p) => p.id === id);
};

const authz = useAuthz();

const fleetStatus = useFleetStatus();
const { docLinks } = useStartServices();

Expand Down Expand Up @@ -172,6 +175,8 @@ export const AgentEnrollmentFlyout: React.FunctionComponent<FlyOutProps> = ({
data-test-subj="standaloneTab"
isSelected={mode === 'standalone'}
onClick={() => setMode('standalone')}
// Standalone need read access to agent policies
disabled={!authz.fleet.readAgentPolicies}
>
<FormattedMessage
id="xpack.fleet.agentEnrollment.enrollStandaloneTabLabel"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,34 @@
*/

import React from 'react';
import { EuiRadioGroup } from '@elastic/eui';
import { EuiRadioGroup, EuiToolTip } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';

import type { EuiContainedStepProps } from '@elastic/eui/src/components/steps/steps';

import { useAuthz } from '../../../hooks';
import type { FlyoutMode } from '../types';

const PermissionWrapper: React.FunctionComponent<{
showTooltip: boolean;
}> = ({ children, showTooltip }) => {
return showTooltip && children ? (
<EuiToolTip
content={
<FormattedMessage
id="xpack.fleet.agentFlyout.standaloneMissingPermissions"
defaultMessage="Read access to Agent Policies is required to see the standalone instructions."
/>
}
>
{children as React.ReactElement}
</EuiToolTip>
) : (
<>{children}</>
);
};

export const InstallationModeSelectionStep = ({
selectedPolicyId,
mode,
Expand All @@ -23,6 +43,7 @@ export const InstallationModeSelectionStep = ({
mode: FlyoutMode;
setMode: (v: FlyoutMode) => void;
}): EuiContainedStepProps => {
const authz = useAuthz();
// radio id has to be unique so that the component works even if appears twice in DOM
const radioSuffix = 'installation_mode_agent_selection';

Expand Down Expand Up @@ -63,22 +84,26 @@ export const InstallationModeSelectionStep = ({
},
{
id: `standalone_${radioSuffix}`,
// Disabled if no agentPolicies read permission
disabled: !authz.fleet.readAgentPolicies,
label: (
<FormattedMessage
data-test-subj="agentFlyoutStandaloneRadioButtons"
id="xpack.fleet.agentFlyout.standaloneRadioOption"
defaultMessage="{standaloneMessage} – Run an Elastic Agent standalone to configure and update the agent manually on the host where the agent is installed."
values={{
standaloneMessage: (
<strong>
<FormattedMessage
id="xpack.fleet.agentFlyout.standaloneMessage"
defaultMessage="Run standalone"
/>
</strong>
),
}}
/>
<PermissionWrapper showTooltip={!authz.fleet.readAgentPolicies}>
<FormattedMessage
data-test-subj="agentFlyoutStandaloneRadioButtons"
id="xpack.fleet.agentFlyout.standaloneRadioOption"
defaultMessage="{standaloneMessage} – Run an Elastic Agent standalone to configure and update the agent manually on the host where the agent is installed."
values={{
standaloneMessage: (
<strong>
<FormattedMessage
id="xpack.fleet.agentFlyout.standaloneMessage"
defaultMessage="Run standalone"
/>
</strong>
),
}}
/>
</PermissionWrapper>
),
},
]}
Expand Down

0 comments on commit c27ca40

Please sign in to comment.