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