Skip to content

Commit

Permalink
chore: UI SCIM guard for groups (#6866)
Browse files Browse the repository at this point in the history
https://linear.app/unleash/issue/2-2113/ui-should-not-allow-manual-management-of-scim-managed-groups-in

Adds a UI SCIM guard when trying to manage groups.

The condition for the guard is:

 - Enterprise
 - SCIM flag enabled
 - SCIM setting enabled
 - SCIM group

Similar to #6859
  • Loading branch information
nunogois committed Apr 17, 2024
1 parent 8b25ebf commit bc07045
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 38 deletions.
31 changes: 21 additions & 10 deletions frontend/src/component/admin/groups/EditGroup/EditGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import useToast from 'hooks/useToast';
import { useGroupApi } from 'hooks/api/actions/useGroupApi/useGroupApi';
import { formatUnknownError } from 'utils/formatUnknownError';
import { Button } from '@mui/material';
import { Button, Tooltip } from '@mui/material';
import { EDIT } from 'constants/misc';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useGroup } from 'hooks/api/getters/useGroup/useGroup';
import { UG_SAVE_BTN_ID } from 'utils/testIds';
import { GO_BACK } from 'constants/navigate';
import { useGroups } from 'hooks/api/getters/useGroups/useGroups';
import type { IGroup } from 'interfaces/group';
import { scimGroupTooltip } from '../group-constants';
import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings';

export const EditGroupContainer = () => {
const groupId = Number(useRequiredPathParam('groupId'));
Expand Down Expand Up @@ -46,6 +48,11 @@ export const EditGroup = ({
const { uiConfig } = useUiConfig();
const navigate = useNavigate();

const {
settings: { enabled: scimEnabled },
} = useScimSettings();
const isScimGroup = scimEnabled && Boolean(group?.scimId);

const {
name,
setName,
Expand Down Expand Up @@ -143,15 +150,19 @@ export const EditGroup = ({
handleCancel={handleCancel}
mode={EDIT}
>
<Button
type='submit'
variant='contained'
color='primary'
disabled={!isValid}
data-testid={UG_SAVE_BTN_ID}
>
Save
</Button>
<Tooltip title={isScimGroup ? scimGroupTooltip : ''} arrow>
<div>
<Button
type='submit'
variant='contained'
color='primary'
disabled={isScimGroup || !isValid}
data-testid={UG_SAVE_BTN_ID}
>
Save
</Button>
</div>
</Tooltip>
</GroupForm>
</FormTemplate>
);
Expand Down
30 changes: 27 additions & 3 deletions frontend/src/component/admin/groups/Group/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import {
UG_EDIT_USERS_BTN_ID,
UG_REMOVE_USER_BTN_ID,
} from 'utils/testIds';
import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings';
import { scimGroupTooltip } from '../group-constants';

export const groupUsersPlaceholder: IGroupUser[] = Array(15).fill({
name: 'Name of the user',
Expand Down Expand Up @@ -68,6 +70,11 @@ export const Group: VFC = () => {
const [removeUserOpen, setRemoveUserOpen] = useState(false);
const [selectedUser, setSelectedUser] = useState<IGroupUser>();

const {
settings: { enabled: scimEnabled },
} = useScimSettings();
const isScimGroup = scimEnabled && Boolean(group?.scimId);

const columns = useMemo(
() => [
{
Expand Down Expand Up @@ -127,7 +134,11 @@ export const Group: VFC = () => {
Cell: ({ row: { original: rowUser } }: any) => (
<ActionCell>
<Tooltip
title='Remove user from group'
title={
isScimGroup
? scimGroupTooltip
: 'Remove user from group'
}
arrow
describeChild
>
Expand All @@ -138,6 +149,7 @@ export const Group: VFC = () => {
setSelectedUser(rowUser);
setRemoveUserOpen(true);
}}
disabled={isScimGroup}
>
<Delete />
</IconButton>
Expand Down Expand Up @@ -245,8 +257,11 @@ export const Group: VFC = () => {
data-loading
permission={ADMIN}
tooltipProps={{
title: 'Edit group',
title: isScimGroup
? scimGroupTooltip
: 'Edit group',
}}
disabled={isScimGroup}
>
<Edit />
</PermissionIconButton>
Expand All @@ -256,8 +271,11 @@ export const Group: VFC = () => {
onClick={() => setRemoveOpen(true)}
permission={ADMIN}
tooltipProps={{
title: 'Delete group',
title: isScimGroup
? scimGroupTooltip
: 'Delete group',
}}
disabled={isScimGroup}
>
<Delete />
</PermissionIconButton>
Expand Down Expand Up @@ -304,6 +322,12 @@ export const Group: VFC = () => {
maxWidth='700px'
Icon={Add}
permission={ADMIN}
disabled={isScimGroup}
tooltipProps={{
title: isScimGroup
? scimGroupTooltip
: '',
}}
>
Edit users
</ResponsiveButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Badge } from 'component/common/Badge/Badge';
import { GroupCardActions } from './GroupCardActions/GroupCardActions';
import TopicOutlinedIcon from '@mui/icons-material/TopicOutlined';
import { RoleBadge } from 'component/common/RoleBadge/RoleBadge';
import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings';

const StyledLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
Expand Down Expand Up @@ -96,6 +97,12 @@ export const GroupCard = ({
onRemoveGroup,
}: IGroupCardProps) => {
const navigate = useNavigate();

const {
settings: { enabled: scimEnabled },
} = useScimSettings();
const isScimGroup = scimEnabled && Boolean(group.scimId);

return (
<>
<StyledLink key={group.id} to={`/admin/groups/${group.id}`}>
Expand All @@ -107,6 +114,7 @@ export const GroupCard = ({
groupId={group.id}
onEditUsers={() => onEditUsers(group)}
onRemove={() => onRemoveGroup(group)}
isScimGroup={isScimGroup}
/>
</StyledHeaderActions>
</StyledTitleRow>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import Edit from '@mui/icons-material/Edit';
import GroupRounded from '@mui/icons-material/GroupRounded';
import MoreVert from '@mui/icons-material/MoreVert';
import { Link } from 'react-router-dom';
import { scimGroupTooltip } from 'component/admin/groups/group-constants';

const StyledActions = styled('div')(({ theme }) => ({
display: 'flex',
Expand All @@ -31,12 +32,14 @@ interface IGroupCardActions {
groupId: number;
onEditUsers: () => void;
onRemove: () => void;
isScimGroup?: boolean;
}

export const GroupCardActions: FC<IGroupCardActions> = ({
groupId,
onEditUsers,
onRemove,
isScimGroup,
}) => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);

Expand All @@ -58,17 +61,24 @@ export const GroupCardActions: FC<IGroupCardActions> = ({
e.stopPropagation();
}}
>
<Tooltip title='Group actions' arrow describeChild>
<IconButton
id={id}
aria-controls={open ? menuId : undefined}
aria-haspopup='true'
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
type='button'
>
<MoreVert />
</IconButton>
<Tooltip
title={isScimGroup ? scimGroupTooltip : 'Group actions'}
arrow
describeChild
>
<div>
<IconButton
id={id}
aria-controls={open ? menuId : undefined}
aria-haspopup='true'
aria-expanded={open ? 'true' : undefined}
onClick={handleClick}
type='button'
disabled={isScimGroup}
>
<MoreVert />
</IconButton>
</div>
</Tooltip>
<StyledPopover
id={menuId}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/component/admin/groups/group-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const scimGroupTooltip =
'This group is managed by your SCIM provider and cannot be changed manually';
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface IUsersActionsCellProps {
onChangePassword: (event: React.SyntheticEvent) => void;
onResetPassword: (event: React.SyntheticEvent) => void;
onDelete: (event: React.SyntheticEvent) => void;
scimEnabled?: boolean;
isScimUser?: boolean;
}

export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
Expand All @@ -29,7 +29,7 @@ export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
onChangePassword,
onResetPassword,
onDelete,
scimEnabled,
isScimUser,
}) => {
const scimTooltip =
'This user is managed by your SCIM provider and cannot be changed manually';
Expand All @@ -41,9 +41,9 @@ export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
onClick={onEdit}
permission={ADMIN}
tooltipProps={{
title: scimEnabled ? scimTooltip : 'Edit user',
title: isScimUser ? scimTooltip : 'Edit user',
}}
disabled={scimEnabled}
disabled={isScimUser}
>
<Edit />
</PermissionIconButton>
Expand All @@ -69,9 +69,9 @@ export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
onClick={onChangePassword}
permission={ADMIN}
tooltipProps={{
title: scimEnabled ? scimTooltip : 'Change password',
title: isScimUser ? scimTooltip : 'Change password',
}}
disabled={scimEnabled}
disabled={isScimUser}
>
<Lock />
</PermissionIconButton>
Expand All @@ -80,9 +80,9 @@ export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
onClick={onResetPassword}
permission={ADMIN}
tooltipProps={{
title: scimEnabled ? scimTooltip : 'Reset password',
title: isScimUser ? scimTooltip : 'Reset password',
}}
disabled={scimEnabled}
disabled={isScimUser}
>
<LockReset />
</PermissionIconButton>
Expand All @@ -91,9 +91,9 @@ export const UsersActionsCell: VFC<IUsersActionsCellProps> = ({
onClick={onDelete}
permission={ADMIN}
tooltipProps={{
title: scimEnabled ? scimTooltip : 'Remove user',
title: isScimUser ? scimTooltip : 'Remove user',
}}
disabled={scimEnabled}
disabled={isScimUser}
>
<Delete />
</PermissionIconButton>
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/component/admin/users/UsersList/UsersList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,8 @@ const UsersList = () => {
});
const userAccessUIEnabled = useUiFlag('userAccessUIEnabled');
const {
settings: { enabled: scimSettingEnabled },
settings: { enabled: scimEnabled },
} = useScimSettings();
const scimFlagEnabled = useUiFlag('scimApi');
const scimEnabled = isEnterprise() && scimSettingEnabled && scimFlagEnabled;
const [delDialog, setDelDialog] = useState(false);
const [showConfirm, setShowConfirm] = useState(false);
const [emailSent, setEmailSent] = useState(false);
Expand Down Expand Up @@ -218,7 +216,7 @@ const UsersList = () => {
onChangePassword={openPwDialog(user)}
onResetPassword={openResetPwDialog(user)}
onDelete={openDelDialog(user)}
scimEnabled={scimEnabled && Boolean(user.scimId)}
isScimUser={scimEnabled && Boolean(user.scimId)}
/>
),
width: userAccessUIEnabled ? 240 : 200,
Expand Down

0 comments on commit bc07045

Please sign in to comment.