Merge pull request #2046 from Infisical/misc/add-check-for-ldap-group

misc: added backend check for ldap group config
This commit is contained in:
Sheen Capadngan
2024-07-02 12:59:03 +08:00
committed by GitHub
2 changed files with 163 additions and 116 deletions

View File

@@ -53,7 +53,7 @@ import {
TTestLdapConnectionDTO, TTestLdapConnectionDTO,
TUpdateLdapCfgDTO TUpdateLdapCfgDTO
} from "./ldap-config-types"; } from "./ldap-config-types";
import { testLDAPConfig } from "./ldap-fns"; import { searchGroups, testLDAPConfig } from "./ldap-fns";
import { TLdapGroupMapDALFactory } from "./ldap-group-map-dal"; import { TLdapGroupMapDALFactory } from "./ldap-group-map-dal";
type TLdapConfigServiceFactoryDep = { type TLdapConfigServiceFactoryDep = {
@@ -286,7 +286,7 @@ export const ldapConfigServiceFactory = ({
return ldapConfig; return ldapConfig;
}; };
const getLdapCfg = async (filter: { orgId: string; isActive?: boolean }) => { const getLdapCfg = async (filter: { orgId: string; isActive?: boolean; id?: string }) => {
const ldapConfig = await ldapConfigDAL.findOne(filter); const ldapConfig = await ldapConfigDAL.findOne(filter);
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" }); if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
@@ -716,11 +716,25 @@ export const ldapConfigServiceFactory = ({
message: "Failed to create LDAP group map due to plan restriction. Upgrade plan to create LDAP group map." message: "Failed to create LDAP group map due to plan restriction. Upgrade plan to create LDAP group map."
}); });
const ldapConfig = await ldapConfigDAL.findOne({ const ldapConfig = await getLdapCfg({
id: ldapConfigId, orgId,
orgId id: ldapConfigId
}); });
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
if (!ldapConfig.groupSearchBase) {
throw new BadRequestError({
message: "Configure a group search base in your LDAP configuration in order to proceed."
});
}
const groupSearchFilter = `(cn=${ldapGroupCN})`;
const groups = await searchGroups(ldapConfig, groupSearchFilter, ldapConfig.groupSearchBase);
if (!groups.some((g) => g.cn === ldapGroupCN)) {
throw new BadRequestError({
message: "Failed to find LDAP Group CN"
});
}
const group = await groupDAL.findOne({ slug: groupSlug, orgId }); const group = await groupDAL.findOne({ slug: groupSlug, orgId });
if (!group) throw new BadRequestError({ message: "Failed to find group" }); if (!group) throw new BadRequestError({ message: "Failed to find group" });

View File

@@ -1,4 +1,6 @@
import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { useRouter } from "next/router";
import { faUsers, faXmark } from "@fortawesome/free-solid-svg-icons"; import { faUsers, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
@@ -66,8 +68,9 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
const { mutateAsync: createLDAPGroupMapping, isLoading: createIsLoading } = const { mutateAsync: createLDAPGroupMapping, isLoading: createIsLoading } =
useCreateLDAPGroupMapping(); useCreateLDAPGroupMapping();
const { mutateAsync: deleteLDAPGroupMapping } = useDeleteLDAPGroupMapping(); const { mutateAsync: deleteLDAPGroupMapping } = useDeleteLDAPGroupMapping();
const router = useRouter();
const { control, handleSubmit, reset } = useForm<TFormData>({ const { control, handleSubmit, reset, setValue } = useForm<TFormData>({
resolver: zodResolver(schema), resolver: zodResolver(schema),
defaultValues: { defaultValues: {
ldapGroupCN: "", ldapGroupCN: "",
@@ -130,6 +133,12 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
} }
}; };
useEffect(() => {
if (groups && groups.length > 0) {
setValue("groupSlug", groups[0].slug);
}
}, [groups, popUp.ldapGroupMap.isOpen]);
return ( return (
<Modal <Modal
isOpen={popUp?.ldapGroupMap?.isOpen} isOpen={popUp?.ldapGroupMap?.isOpen}
@@ -139,117 +148,141 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
}} }}
> >
<ModalContent title="Manage LDAP Group Mappings"> <ModalContent title="Manage LDAP Group Mappings">
<h2 className="mb-4">New Group Mapping</h2> {groups && groups.length > 0 && (
<form onSubmit={handleSubmit(onFormSubmit)} className="mb-8"> <>
<div className="flex"> <h2 className="mb-4">New Group Mapping</h2>
<Controller <form onSubmit={handleSubmit(onFormSubmit)} className="mb-8">
control={control} <div className="flex">
name="ldapGroupCN" <Controller
render={({ field, fieldState: { error } }) => ( control={control}
<FormControl name="ldapGroupCN"
label="LDAP Group CN" render={({ field, fieldState: { error } }) => (
errorText={error?.message} <FormControl
isError={Boolean(error)} label="LDAP Group CN"
> errorText={error?.message}
<Input {...field} placeholder="Engineering" /> isError={Boolean(error)}
</FormControl>
)}
/>
<Controller
control={control}
name="groupSlug"
defaultValue=""
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="Infisical Group"
errorText={error?.message}
isError={Boolean(error)}
className="ml-4 w-full"
>
<div className="flex">
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
> >
{(groups || []).map(({ name, id, slug }) => ( <Input {...field} placeholder="Engineering" />
<SelectItem value={slug} key={`internal-group-${id}`}> </FormControl>
{name} )}
</SelectItem> />
))} <Controller
</Select> control={control}
<Button className="ml-4" size="sm" type="submit" isLoading={createIsLoading}> name="groupSlug"
Add mapping defaultValue=""
</Button> render={({ field: { onChange, ...field }, fieldState: { error } }) => (
</div> <FormControl
</FormControl> label="Infisical Group"
)} errorText={error?.message}
/> isError={Boolean(error)}
</div> className="ml-4 w-full"
</form> >
<h2 className="mb-4">Group Mappings</h2> <div className="flex">
<TableContainer> <Select
<Table> defaultValue={field.value}
<THead> {...field}
<Tr> onValueChange={(e) => onChange(e)}
<Th>LDAP Group CN</Th> className="w-full"
<Th>Infisical Group</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{isLoading && <TableSkeleton columns={3} innerKey="ldap-group-maps" />}
{!isLoading &&
groupMaps?.map(({ id, ldapGroupCN, group }) => {
return (
<Tr className="h-10 items-center" key={`ldap-group-map-${id}`}>
<Td>{ldapGroupCN}</Td>
<Td>{group.name}</Td>
<Td>
<IconButton
onClick={() => {
handlePopUpOpen("deleteLdapGroupMap", {
ldapGroupMapId: id,
ldapGroupCN
});
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
> >
<FontAwesomeIcon icon={faXmark} /> {(groups || []).map(({ name, id, slug }) => (
</IconButton> <SelectItem value={slug} key={`internal-group-${id}`}>
</Td> {name}
</Tr> </SelectItem>
); ))}
})} </Select>
</TBody> <Button
</Table> className="ml-4"
{groupMaps?.length === 0 && ( size="sm"
<EmptyState title="No LDAP group mappings found" icon={faUsers} /> type="submit"
)} isLoading={createIsLoading}
</TableContainer> >
<DeleteActionModal Add mapping
isOpen={popUp.deleteLdapGroupMap.isOpen} </Button>
title={`Are you sure want to delete the group mapping for ${ </div>
(popUp?.deleteLdapGroupMap?.data as { ldapGroupCN: string })?.ldapGroupCN || "" </FormControl>
}?`} )}
onChange={(isOpen) => handlePopUpToggle("deleteLdapGroupMap", isOpen)} />
deleteKey="confirm" </div>
onDeleteApproved={() => { </form>
const deleteLdapGroupMapData = popUp?.deleteLdapGroupMap?.data as { <h2 className="mb-4">Group Mappings</h2>
ldapGroupMapId: string; <TableContainer>
ldapGroupCN: string; <Table>
}; <THead>
return onDeleteGroupMapSubmit({ <Tr>
ldapConfigId: ldapConfig?.id ?? "", <Th>LDAP Group CN</Th>
ldapGroupMapId: deleteLdapGroupMapData.ldapGroupMapId, <Th>Infisical Group</Th>
ldapGroupCN: deleteLdapGroupMapData.ldapGroupCN <Th className="w-5" />
}); </Tr>
}} </THead>
/> <TBody>
{isLoading && <TableSkeleton columns={3} innerKey="ldap-group-maps" />}
{!isLoading &&
groupMaps?.map(({ id, ldapGroupCN, group }) => {
return (
<Tr className="h-10 items-center" key={`ldap-group-map-${id}`}>
<Td>{ldapGroupCN}</Td>
<Td>{group.name}</Td>
<Td>
<IconButton
onClick={() => {
handlePopUpOpen("deleteLdapGroupMap", {
ldapGroupMapId: id,
ldapGroupCN
});
}}
size="lg"
colorSchema="danger"
variant="plain"
ariaLabel="update"
>
<FontAwesomeIcon icon={faXmark} />
</IconButton>
</Td>
</Tr>
);
})}
</TBody>
</Table>
{groupMaps?.length === 0 && (
<EmptyState title="No LDAP group mappings found" icon={faUsers} />
)}
</TableContainer>
<DeleteActionModal
isOpen={popUp.deleteLdapGroupMap.isOpen}
title={`Are you sure want to delete the group mapping for ${
(popUp?.deleteLdapGroupMap?.data as { ldapGroupCN: string })?.ldapGroupCN || ""
}?`}
onChange={(isOpen) => handlePopUpToggle("deleteLdapGroupMap", isOpen)}
deleteKey="confirm"
onDeleteApproved={() => {
const deleteLdapGroupMapData = popUp?.deleteLdapGroupMap?.data as {
ldapGroupMapId: string;
ldapGroupCN: string;
};
return onDeleteGroupMapSubmit({
ldapConfigId: ldapConfig?.id ?? "",
ldapGroupMapId: deleteLdapGroupMapData.ldapGroupMapId,
ldapGroupCN: deleteLdapGroupMapData.ldapGroupCN
});
}}
/>
</>
)}
{groups && groups.length === 0 && (
<div>
<div>
You do not have any Infisical groups in your organization. Create one in order to
proceed.
</div>
<Button
className="mt-4"
size="sm"
onClick={() => router.push(`/org/${currentOrg?.id}/members`)}
>
Create
</Button>
</div>
)}
</ModalContent> </ModalContent>
</Modal> </Modal>
); );