mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: add support for removing instance admin permission from identity
This commit is contained in:
@@ -399,6 +399,42 @@ export const registerAdminRouter = async (server: FastifyZodProvider) => {
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "DELETE",
|
||||
url: "/identity-management/identities/:identityId/super-admin-access",
|
||||
config: {
|
||||
rateLimit: writeLimit
|
||||
},
|
||||
schema: {
|
||||
params: z.object({
|
||||
identityId: z.string()
|
||||
}),
|
||||
response: {
|
||||
200: z.object({
|
||||
identity: IdentitiesSchema.pick({
|
||||
name: true,
|
||||
id: true
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
onRequest: (req, res, done) => {
|
||||
verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN])(req, res, () => {
|
||||
verifySuperAdmin(req, res, done);
|
||||
});
|
||||
},
|
||||
handler: async (req) => {
|
||||
const identity = await server.services.superAdmin.deleteIdentitySuperAdminAccess(
|
||||
req.params.identityId,
|
||||
req.permission.id
|
||||
);
|
||||
|
||||
return {
|
||||
identity
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
server.route({
|
||||
method: "POST",
|
||||
url: "/bootstrap",
|
||||
|
||||
@@ -437,6 +437,22 @@ export const superAdminServiceFactory = ({
|
||||
return user;
|
||||
};
|
||||
|
||||
const deleteIdentitySuperAdminAccess = async (identityId: string, actorId: string) => {
|
||||
const identity = await identityDAL.findById(identityId);
|
||||
if (!identity) {
|
||||
throw new NotFoundError({ name: "Identity", message: "Identity not found" });
|
||||
}
|
||||
|
||||
const currentAdminIdentityIds = (await getServerCfg()).adminIdentityIds ?? [];
|
||||
if (!currentAdminIdentityIds?.includes(identityId)) {
|
||||
throw new BadRequestError({ name: "Identity", message: "Identity does not have super admin access" });
|
||||
}
|
||||
|
||||
await updateServerCfg({ adminIdentityIds: currentAdminIdentityIds.filter((id) => id !== identityId) }, actorId);
|
||||
|
||||
return identity;
|
||||
};
|
||||
|
||||
const getIdentities = async ({ offset, limit, searchTerm }: TAdminGetIdentitiesDTO) => {
|
||||
const identities = await identityDAL.getIdentitiesByFilter({
|
||||
limit,
|
||||
@@ -554,6 +570,7 @@ export const superAdminServiceFactory = ({
|
||||
getAdminSlackConfig,
|
||||
updateRootEncryptionStrategy,
|
||||
getConfiguredEncryptionStrategies,
|
||||
grantServerAdminAccessToUser
|
||||
grantServerAdminAccessToUser,
|
||||
deleteIdentitySuperAdminAccess
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export {
|
||||
useAdminDeleteUser,
|
||||
useAdminGrantServerAdminAccess,
|
||||
useAdminRemoveIdentitySuperAdminAccess,
|
||||
useCreateAdminUser,
|
||||
useUpdateAdminSlackConfig,
|
||||
useUpdateServerConfig,
|
||||
|
||||
@@ -70,6 +70,24 @@ export const useAdminDeleteUser = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useAdminRemoveIdentitySuperAdminAccess = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async (identityId: string) => {
|
||||
await apiRequest.delete(
|
||||
`/api/v1/admin/identity-management/identities/${identityId}/super-admin-access`
|
||||
);
|
||||
|
||||
return {};
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [adminStandaloneKeys.getIdentities]
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useAdminGrantServerAdminAccess = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { useState } from "react";
|
||||
import { faMagnifyingGlass, faServer } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faEllipsis, faMagnifyingGlass, faServer } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
DeleteActionModal,
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
EmptyState,
|
||||
Input,
|
||||
Table,
|
||||
@@ -16,10 +22,22 @@ import {
|
||||
THead,
|
||||
Tr
|
||||
} from "@app/components/v2";
|
||||
import { useDebounce } from "@app/hooks";
|
||||
import { useDebounce, usePopUp } from "@app/hooks";
|
||||
import { useAdminRemoveIdentitySuperAdminAccess } from "@app/hooks/api/admin";
|
||||
import { useAdminGetIdentities } from "@app/hooks/api/admin/queries";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const IdentityPanelTable = () => {
|
||||
const IdentityPanelTable = ({
|
||||
handlePopUpOpen
|
||||
}: {
|
||||
handlePopUpOpen: (
|
||||
popUpName: keyof UsePopUpState<["removeServerAdmin"]>,
|
||||
data?: {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
) => void;
|
||||
}) => {
|
||||
const [searchIdentityFilter, setSearchIdentityFilter] = useState("");
|
||||
const [debouncedSearchTerm] = useDebounce(searchIdentityFilter, 500);
|
||||
|
||||
@@ -49,6 +67,7 @@ const IdentityPanelTable = () => {
|
||||
<THead>
|
||||
<Tr>
|
||||
<Th>Name</Th>
|
||||
<Th className="w-5" />
|
||||
</Tr>
|
||||
</THead>
|
||||
<TBody>
|
||||
@@ -65,6 +84,31 @@ const IdentityPanelTable = () => {
|
||||
</Badge>
|
||||
)}
|
||||
</Td>
|
||||
<Td>
|
||||
{isInstanceAdmin && (
|
||||
<div className="flex justify-end">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild className="rounded-lg">
|
||||
<div className="hover:text-primary-400 data-[state=open]:text-primary-400">
|
||||
<FontAwesomeIcon size="sm" icon={faEllipsis} />
|
||||
</div>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" className="p-1">
|
||||
{isInstanceAdmin && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handlePopUpOpen("removeServerAdmin", { name, id });
|
||||
}}
|
||||
>
|
||||
Remove Server Admin
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
)}
|
||||
</Td>
|
||||
</Tr>
|
||||
))
|
||||
)}
|
||||
@@ -89,11 +133,49 @@ const IdentityPanelTable = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const IdentityPanel = () => (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Identities</p>
|
||||
export const IdentityPanel = () => {
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
|
||||
"removeServerAdmin"
|
||||
] as const);
|
||||
|
||||
const { mutate: deleteIdentitySuperAdminAccess } = useAdminRemoveIdentitySuperAdminAccess();
|
||||
|
||||
const handleRemoveServerAdmin = async () => {
|
||||
const { id } = popUp?.removeServerAdmin?.data as { id: string; name: string };
|
||||
|
||||
try {
|
||||
await deleteIdentitySuperAdminAccess(id);
|
||||
createNotification({
|
||||
type: "success",
|
||||
text: "Successfully removed server admin permissions"
|
||||
});
|
||||
} catch {
|
||||
createNotification({
|
||||
type: "error",
|
||||
text: "Error removing server admin permissions"
|
||||
});
|
||||
}
|
||||
|
||||
handlePopUpClose("removeServerAdmin");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||
<div className="mb-4">
|
||||
<p className="text-xl font-semibold text-mineshaft-100">Identities</p>
|
||||
</div>
|
||||
<IdentityPanelTable handlePopUpOpen={handlePopUpOpen} />
|
||||
<DeleteActionModal
|
||||
isOpen={popUp.removeServerAdmin.isOpen}
|
||||
title={`Are you sure want to remove Server Admin permissions from ${
|
||||
(popUp?.removeServerAdmin?.data as { name: string })?.name || ""
|
||||
}?`}
|
||||
subTitle=""
|
||||
onChange={(isOpen) => handlePopUpToggle("removeServerAdmin", isOpen)}
|
||||
deleteKey="confirm"
|
||||
onDeleteApproved={handleRemoveServerAdmin}
|
||||
buttonText="Remove Access"
|
||||
/>
|
||||
</div>
|
||||
<IdentityPanelTable />
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user