mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Update ldap group mapping schema, replace group input field with select
This commit is contained in:
@@ -10,8 +10,9 @@ export async function up(knex: Knex): Promise<void> {
|
||||
t.uuid("ldapConfigId").notNullable();
|
||||
t.foreign("ldapConfigId").references("id").inTable(TableName.LdapConfig).onDelete("CASCADE");
|
||||
t.string("ldapGroupCN").notNullable();
|
||||
t.string("groupSlug").notNullable();
|
||||
t.unique(["ldapGroupCN", "groupSlug", "ldapConfigId"]);
|
||||
t.uuid("groupId").notNullable();
|
||||
t.foreign("groupId").references("id").inTable(TableName.Groups).onDelete("CASCADE");
|
||||
t.unique(["ldapGroupCN", "groupId", "ldapConfigId"]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ export const LdapGroupMapsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
ldapConfigId: z.string().uuid(),
|
||||
ldapGroupCN: z.string(),
|
||||
groupSlug: z.string()
|
||||
groupId: z.string().uuid()
|
||||
});
|
||||
|
||||
export type TLdapGroupMaps = z.infer<typeof LdapGroupMapsSchema>;
|
||||
|
||||
@@ -71,6 +71,7 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
||||
// If group search values are not provided, proceed directly to LDAP login
|
||||
return await server.services.ldap
|
||||
.ldapLogin({
|
||||
ldapConfigId: ldapConfig.id,
|
||||
externalId: user.uidNumber,
|
||||
username: user.uid,
|
||||
firstName: user.givenName,
|
||||
@@ -111,6 +112,7 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
||||
// groups here
|
||||
ldapClient.unbind();
|
||||
return server.services.ldap.ldapLogin({
|
||||
ldapConfigId: ldapConfig.id,
|
||||
externalId: user.uidNumber,
|
||||
username: user.uid,
|
||||
firstName: user.givenName,
|
||||
@@ -292,7 +294,18 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
||||
configId: z.string().trim()
|
||||
}),
|
||||
response: {
|
||||
200: z.array(LdapGroupMapsSchema)
|
||||
200: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
ldapConfigId: z.string(),
|
||||
ldapGroupCN: z.string(),
|
||||
group: z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
slug: z.string()
|
||||
})
|
||||
})
|
||||
)
|
||||
}
|
||||
},
|
||||
handler: async (req) => {
|
||||
|
||||
@@ -37,7 +37,7 @@ import { TLdapGroupMapDALFactory } from "./ldap-group-map-dal";
|
||||
|
||||
type TLdapConfigServiceFactoryDep = {
|
||||
ldapConfigDAL: Pick<TLdapConfigDALFactory, "create" | "update" | "findOne">;
|
||||
ldapGroupMapDAL: Pick<TLdapGroupMapDALFactory, "find" | "create" | "delete">;
|
||||
ldapGroupMapDAL: Pick<TLdapGroupMapDALFactory, "find" | "create" | "delete" | "findLdapGroupMapsByLdapConfigId">;
|
||||
orgDAL: Pick<
|
||||
TOrgDALFactory,
|
||||
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" | "findOne" | "updateById"
|
||||
@@ -57,6 +57,7 @@ export const ldapConfigServiceFactory = ({
|
||||
ldapGroupMapDAL,
|
||||
orgDAL,
|
||||
orgBotDAL,
|
||||
groupDAL,
|
||||
userDAL,
|
||||
userAliasDAL,
|
||||
permissionService,
|
||||
@@ -343,7 +344,17 @@ export const ldapConfigServiceFactory = ({
|
||||
return { opts, ldapConfig };
|
||||
};
|
||||
|
||||
const ldapLogin = async ({ externalId, username, firstName, lastName, emails, orgId, relayState }: TLdapLoginDTO) => {
|
||||
const ldapLogin = async ({
|
||||
// ldapConfigId,
|
||||
externalId,
|
||||
username,
|
||||
firstName,
|
||||
lastName,
|
||||
emails,
|
||||
groups,
|
||||
orgId,
|
||||
relayState
|
||||
}: TLdapLoginDTO) => {
|
||||
const appCfg = getConfig();
|
||||
let userAlias = await userAliasDAL.findOne({
|
||||
externalId,
|
||||
@@ -419,23 +430,28 @@ export const ldapConfigServiceFactory = ({
|
||||
|
||||
const user = await userDAL.findOne({ id: userAlias.userId });
|
||||
|
||||
// if (groups) { // TODO
|
||||
// /**
|
||||
// * TODO:
|
||||
// * - Query for groups matching name
|
||||
// * - Provision, de-provision user to groups accordingly
|
||||
// */
|
||||
|
||||
// console.log("there are groups");
|
||||
|
||||
// const matchingGroups = await groupDAL.find({
|
||||
// $in: {
|
||||
// name: groups.map((group) => group.cn)
|
||||
// }
|
||||
// });
|
||||
|
||||
// console.log("found matching groups");
|
||||
// }
|
||||
if (groups) {
|
||||
// TODO
|
||||
// const m = await ldapGroupMapDAL.find({
|
||||
// ldapConfigId,
|
||||
// $in: {
|
||||
// ldapGroupCN: groups.map((group) => group.cn)
|
||||
// }
|
||||
// });
|
||||
/**
|
||||
* TODO:
|
||||
* - Find relevant group maps
|
||||
* - Query for groups matching name
|
||||
* - Provision, de-provision user to groups accordingly
|
||||
*/
|
||||
// console.log("there are groups");
|
||||
// const matchingGroups = await groupDAL.find({
|
||||
// $in: {
|
||||
// name: groups.map((group) => group.cn)
|
||||
// }
|
||||
// });
|
||||
// console.log("found matching groups");
|
||||
}
|
||||
|
||||
const isUserCompleted = Boolean(user.isAccepted);
|
||||
|
||||
@@ -483,9 +499,7 @@ export const ldapConfigServiceFactory = ({
|
||||
|
||||
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
|
||||
|
||||
const groupMaps = await ldapGroupMapDAL.find({
|
||||
ldapConfigId
|
||||
});
|
||||
const groupMaps = await ldapGroupMapDAL.findLdapGroupMapsByLdapConfigId(ldapConfigId);
|
||||
|
||||
return groupMaps;
|
||||
};
|
||||
@@ -507,13 +521,15 @@ export const ldapConfigServiceFactory = ({
|
||||
id: ldapConfigId,
|
||||
orgId
|
||||
});
|
||||
|
||||
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
|
||||
|
||||
const group = await groupDAL.findOne({ slug: groupSlug, orgId });
|
||||
if (!group) throw new BadRequestError({ message: "Failed to find group" });
|
||||
|
||||
const groupMap = await ldapGroupMapDAL.create({
|
||||
ldapConfigId,
|
||||
ldapGroupCN,
|
||||
groupSlug
|
||||
groupId: group.id
|
||||
});
|
||||
|
||||
return groupMap;
|
||||
|
||||
@@ -31,6 +31,7 @@ export type TGetLdapCfgDTO = {
|
||||
} & TOrgPermission;
|
||||
|
||||
export type TLdapLoginDTO = {
|
||||
ldapConfigId: string;
|
||||
externalId: string;
|
||||
username: string;
|
||||
firstName: string;
|
||||
|
||||
@@ -1,11 +1,41 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
import { DatabaseError } from "@app/lib/errors";
|
||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||
|
||||
export type TLdapGroupMapDALFactory = ReturnType<typeof ldapGroupMapDALFactory>;
|
||||
|
||||
export const ldapGroupMapDALFactory = (db: TDbClient) => {
|
||||
const ldapGroupMapOrm = ormify(db, TableName.LdapGroupMap);
|
||||
|
||||
return { ...ldapGroupMapOrm };
|
||||
const findLdapGroupMapsByLdapConfigId = async (ldapConfigId: string) => {
|
||||
try {
|
||||
const docs = await db(TableName.LdapGroupMap)
|
||||
.where(`${TableName.LdapGroupMap}.ldapConfigId`, ldapConfigId)
|
||||
.join(TableName.Groups, `${TableName.LdapGroupMap}.groupId`, `${TableName.Groups}.id`)
|
||||
.select(selectAllTableCols(TableName.LdapGroupMap))
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.Groups).as("groupId"),
|
||||
db.ref("name").withSchema(TableName.Groups).as("groupSlug"),
|
||||
db.ref("slug").withSchema(TableName.Groups).as("groupName")
|
||||
);
|
||||
|
||||
return docs.map((doc) => {
|
||||
return {
|
||||
id: doc.id,
|
||||
ldapConfigId: doc.ldapConfigId,
|
||||
ldapGroupCN: doc.ldapGroupCN,
|
||||
group: {
|
||||
id: doc.groupId,
|
||||
name: doc.groupName,
|
||||
slug: doc.groupSlug
|
||||
}
|
||||
};
|
||||
});
|
||||
} catch (error) {
|
||||
throw new DatabaseError({ error, name: "findGroupMaps" });
|
||||
}
|
||||
};
|
||||
|
||||
return { ...ldapGroupMapOrm, findLdapGroupMapsByLdapConfigId };
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ export const getDefaultOnPremFeatures = () => {
|
||||
samlSSO: false,
|
||||
scim: false,
|
||||
ldap: true,
|
||||
groups: false,
|
||||
groups: true,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true,
|
||||
|
||||
@@ -27,7 +27,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
||||
samlSSO: false,
|
||||
scim: false,
|
||||
ldap: true,
|
||||
groups: false,
|
||||
groups: true,
|
||||
status: null,
|
||||
trial_end: null,
|
||||
has_used_trial: true,
|
||||
|
||||
@@ -43,7 +43,7 @@ export type TFeatureSet = {
|
||||
samlSSO: false;
|
||||
scim: false;
|
||||
ldap: true;
|
||||
groups: false;
|
||||
groups: true;
|
||||
status: null;
|
||||
trial_end: null;
|
||||
has_used_trial: true;
|
||||
|
||||
@@ -2,5 +2,9 @@ export type LDAPGroupMap = {
|
||||
id: string;
|
||||
ldapConfigId: string;
|
||||
ldapGroupCN: string;
|
||||
groupSlug: string;
|
||||
group: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -14,6 +14,8 @@ import {
|
||||
Input,
|
||||
Modal,
|
||||
ModalContent,
|
||||
Select,
|
||||
SelectItem,
|
||||
Table,
|
||||
TableContainer,
|
||||
TableSkeleton,
|
||||
@@ -27,7 +29,9 @@ import {
|
||||
useCreateLDAPGroupMapping,
|
||||
useDeleteLDAPGroupMapping,
|
||||
useGetLDAPConfig,
|
||||
useGetLDAPGroupMaps} from "@app/hooks/api";
|
||||
useGetLDAPGroupMaps,
|
||||
useGetOrganizationGroups
|
||||
} from "@app/hooks/api";
|
||||
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||
|
||||
const schema = z.object({
|
||||
@@ -56,6 +60,7 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
|
||||
const { currentOrg } = useOrganization();
|
||||
|
||||
const { data: ldapConfig } = useGetLDAPConfig(currentOrg?.id ?? "");
|
||||
const { data: groups } = useGetOrganizationGroups(currentOrg?.id ?? "");
|
||||
const { data: groupMaps, isLoading } = useGetLDAPGroupMaps(ldapConfig?.id ?? "");
|
||||
const { mutateAsync: createLDAPGroupMapping, isLoading: createIsLoading } =
|
||||
useCreateLDAPGroupMapping();
|
||||
@@ -152,15 +157,27 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
|
||||
<Controller
|
||||
control={control}
|
||||
name="groupSlug"
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
defaultValue=""
|
||||
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Group Slug"
|
||||
label="Infisical Group"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error)}
|
||||
className="ml-4"
|
||||
className="ml-4 w-full"
|
||||
>
|
||||
<div className="flex">
|
||||
<Input {...field} placeholder="engineering" />
|
||||
<Select
|
||||
defaultValue={field.value}
|
||||
{...field}
|
||||
onValueChange={(e) => onChange(e)}
|
||||
className="w-full"
|
||||
>
|
||||
{(groups || []).map(({ name, id, slug }) => (
|
||||
<SelectItem value={slug} key={`internal-group-${id}`}>
|
||||
{name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
<Button className="ml-4" size="sm" type="submit" isLoading={createIsLoading}>
|
||||
Add mapping
|
||||
</Button>
|
||||
@@ -183,11 +200,11 @@ export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }:
|
||||
<TBody>
|
||||
{isLoading && <TableSkeleton columns={3} innerKey="ldap-group-maps" />}
|
||||
{!isLoading &&
|
||||
groupMaps?.map(({ id, ldapGroupCN, groupSlug }) => {
|
||||
groupMaps?.map(({ id, ldapGroupCN, group: { name } }) => {
|
||||
return (
|
||||
<Tr className="h-10 items-center" key={`ldap-group-map-${id}`}>
|
||||
<Td>{ldapGroupCN}</Td>
|
||||
<Td>{groupSlug}</Td>
|
||||
<Td>{name}</Td>
|
||||
<Td>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
|
||||
@@ -83,7 +83,6 @@ export const OrgLDAPSection = (): JSX.Element => {
|
||||
};
|
||||
|
||||
const openLDAPGroupMapModal = () => {
|
||||
console.log("openLDAPGroupMapModal sub: ", subscription);
|
||||
if (!subscription?.ldap) {
|
||||
handlePopUpOpen("upgradePlan");
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user