diff --git a/frontend/src/component/admin/auth/ScimSettings/ScimDeleteUsersDialog.tsx b/frontend/src/component/admin/auth/ScimSettings/ScimDeleteUsersDialog.tsx new file mode 100644 index 0000000000..f3fc0dab12 --- /dev/null +++ b/frontend/src/component/admin/auth/ScimSettings/ScimDeleteUsersDialog.tsx @@ -0,0 +1,36 @@ +import { Alert, styled, Typography } from '@mui/material'; +import { Dialogue } from 'component/common/Dialogue/Dialogue'; + +const StyledAlert = styled(Alert)(({ theme }) => ({ + marginBottom: theme.spacing(3), +})); + +export type EntityType = 'Users' | 'Groups'; + +interface IScimDeleteUsersProps { + open: boolean; + entityType: EntityType; + closeDialog: () => void; + deleteEntities: () => void; +} + +export const ScimDeleteEntityDialog = ({ + open, + closeDialog, + deleteEntities: removeUser, + entityType, +}: IScimDeleteUsersProps) => ( + + + This will delete all {entityType.toLocaleLowerCase()} created or + managed by SCIM. + + +); diff --git a/frontend/src/component/admin/auth/ScimSettings/ScimSettings.tsx b/frontend/src/component/admin/auth/ScimSettings/ScimSettings.tsx index 5efcee8330..a0a404a1b4 100644 --- a/frontend/src/component/admin/auth/ScimSettings/ScimSettings.tsx +++ b/frontend/src/component/admin/auth/ScimSettings/ScimSettings.tsx @@ -9,6 +9,8 @@ import { formatUnknownError } from 'utils/formatUnknownError'; import useToast from 'hooks/useToast'; import { useScimSettingsApi } from 'hooks/api/actions/useScimSettingsApi/useScimSettingsApi'; import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings'; +import { ScimDeleteEntityDialog } from './ScimDeleteUsersDialog'; +import useAdminUsersApi from 'hooks/api/actions/useAdminUsersApi/useAdminUsersApi'; const StyledContainer = styled('div')(({ theme }) => ({ padding: theme.spacing(3), @@ -25,8 +27,11 @@ export const ScimSettings = () => { const { setToastData, setToastApiError } = useToast(); const [newToken, setNewToken] = useState(''); const [tokenGenerationDialog, setTokenGenerationDialog] = useState(false); + const [deleteGroupsDialog, setDeleteGroupsDialog] = useState(false); + const [deleteUsersDialog, setDeleteUsersDialog] = useState(false); const [tokenDialog, setTokenDialog] = useState(false); const { settings, refetch } = useScimSettings(); + const { deleteScimUsers } = useAdminUsersApi(); const [enabled, setEnabled] = useState(settings.enabled ?? true); useEffect(() => { @@ -40,6 +45,24 @@ export const ScimSettings = () => { setTokenGenerationDialog(true); }; + const onDeleteScimGroups = async () => { + setDeleteGroupsDialog(true); + }; + + const onDeleteScimUsers = async () => { + try { + await deleteScimUsers(); + setToastData({ + text: 'Scim Users have been deleted', + type: 'success', + }); + setDeleteUsersDialog(false); + refetch(); + } catch (error: unknown) { + setToastApiError(formatUnknownError(error)); + } + }; + const onGenerateNewTokenConfirm = async () => { setTokenGenerationDialog(false); const token = await generateNewToken(); @@ -138,6 +161,55 @@ export const ScimSettings = () => { /> + + + + + Delete SCIM Users + +

+ This will remove all SCIM users from the Unleash + database. This action cannot be undone through + Unleash but the upstream SCIM provider may re sync + these users. +

+
+ + + + + + Clear SCIM Groups + +

+ This will remove all SCIM groups from the Unleash + database. This action cannot be undone through + Unleash but the upstream SCIM provider may re sync + these groups. Note that this may affect the + permissions of users present in those groups. +

+
+ + + +
+ { setOpen={setTokenDialog} token={newToken} /> + + setDeleteUsersDialog(false)} + deleteEntities={onDeleteScimUsers} + entityType='Users' + > + + setDeleteGroupsDialog(false)} + deleteEntities={onDeleteScimGroups} + entityType='Groups' + > ); diff --git a/frontend/src/hooks/api/actions/useAdminUsersApi/useAdminUsersApi.ts b/frontend/src/hooks/api/actions/useAdminUsersApi/useAdminUsersApi.ts index ec71c06ded..72ce0e341a 100644 --- a/frontend/src/hooks/api/actions/useAdminUsersApi/useAdminUsersApi.ts +++ b/frontend/src/hooks/api/actions/useAdminUsersApi/useAdminUsersApi.ts @@ -94,6 +94,19 @@ const useAdminUsersApi = () => { return makeRequest(req.caller, req.id); }; + const deleteScimUsers = async () => { + const requestId = 'deleteScimUsers'; + const req = createRequest( + 'api/admin/user-admin/scim-users', + { + method: 'DELETE', + }, + requestId, + ); + + return makeRequest(req.caller, req.id); + }; + return { addUser, updateUser, @@ -101,6 +114,7 @@ const useAdminUsersApi = () => { changePassword, validatePassword, resetPassword, + deleteScimUsers, userApiErrors: errors, userLoading: loading, }; diff --git a/src/lib/routes/admin-api/user-admin.ts b/src/lib/routes/admin-api/user-admin.ts index acfc87132a..986f759c5f 100644 --- a/src/lib/routes/admin-api/user-admin.ts +++ b/src/lib/routes/admin-api/user-admin.ts @@ -411,6 +411,26 @@ export default class UserAdminController extends Controller { ], }); + this.route({ + method: 'delete', + path: '/scim-users', + acceptAnyContentType: true, + handler: this.deleteScimUsers, + permission: ADMIN, + middleware: [ + openApiService.validPath({ + tags: ['Users'], + operationId: 'deleteScimUsers', + summary: 'Delete all SCIM users', + description: 'Deletes all users managed by SCIM', + responses: { + 200: emptyResponse, + ...getStandardResponses(401, 403), + }, + }), + ], + }); + this.route({ method: 'delete', path: '/:id', @@ -441,26 +461,6 @@ export default class UserAdminController extends Controller { }), ], }); - - //add a method to delete all scim users - this.route({ - method: 'delete', - path: '/scim-users', - handler: this.deleteScimUsers, - permission: ADMIN, - middleware: [ - openApiService.validPath({ - tags: ['Users'], - operationId: 'deleteScimUsers', - summary: 'Delete all SCIM users', - description: 'Deletes all users managed by SCIM', - responses: { - 200: emptyResponse, - ...getStandardResponses(401, 403), - }, - }), - ], - }); } async resetUserPassword(