mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 16:27:46 +00:00
Complete LDAP group mapping data structure + frontend/backend
This commit is contained in:
Vendored
+4
@@ -74,6 +74,9 @@ import {
|
|||||||
TLdapConfigs,
|
TLdapConfigs,
|
||||||
TLdapConfigsInsert,
|
TLdapConfigsInsert,
|
||||||
TLdapConfigsUpdate,
|
TLdapConfigsUpdate,
|
||||||
|
TLdapGroupMaps,
|
||||||
|
TLdapGroupMapsInsert,
|
||||||
|
TLdapGroupMapsUpdate,
|
||||||
TOrganizations,
|
TOrganizations,
|
||||||
TOrganizationsInsert,
|
TOrganizationsInsert,
|
||||||
TOrganizationsUpdate,
|
TOrganizationsUpdate,
|
||||||
@@ -398,6 +401,7 @@ declare module "knex/types/tables" {
|
|||||||
>;
|
>;
|
||||||
[TableName.SamlConfig]: Knex.CompositeTableType<TSamlConfigs, TSamlConfigsInsert, TSamlConfigsUpdate>;
|
[TableName.SamlConfig]: Knex.CompositeTableType<TSamlConfigs, TSamlConfigsInsert, TSamlConfigsUpdate>;
|
||||||
[TableName.LdapConfig]: Knex.CompositeTableType<TLdapConfigs, TLdapConfigsInsert, TLdapConfigsUpdate>;
|
[TableName.LdapConfig]: Knex.CompositeTableType<TLdapConfigs, TLdapConfigsInsert, TLdapConfigsUpdate>;
|
||||||
|
[TableName.LdapGroupMap]: Knex.CompositeTableType<TLdapGroupMaps, TLdapGroupMapsInsert, TLdapGroupMapsUpdate>;
|
||||||
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
[TableName.OrgBot]: Knex.CompositeTableType<TOrgBots, TOrgBotsInsert, TOrgBotsUpdate>;
|
||||||
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
[TableName.AuditLog]: Knex.CompositeTableType<TAuditLogs, TAuditLogsInsert, TAuditLogsUpdate>;
|
||||||
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
[TableName.GitAppInstallSession]: Knex.CompositeTableType<
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
|
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
if (!(await knex.schema.hasTable(TableName.LdapGroupMap))) {
|
||||||
|
await knex.schema.createTable(TableName.LdapGroupMap, (t) => {
|
||||||
|
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
||||||
|
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"]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await createOnUpdateTrigger(knex, TableName.LdapGroupMap);
|
||||||
|
|
||||||
await knex.schema.alterTable(TableName.LdapConfig, (t) => {
|
await knex.schema.alterTable(TableName.LdapConfig, (t) => {
|
||||||
t.string("groupSearchBase").notNullable().defaultTo("");
|
t.string("groupSearchBase").notNullable().defaultTo("");
|
||||||
t.string("groupSearchFilter").notNullable().defaultTo("");
|
t.string("groupSearchFilter").notNullable().defaultTo("");
|
||||||
@@ -10,6 +24,8 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
await knex.schema.dropTableIfExists(TableName.LdapGroupMap);
|
||||||
|
await dropOnUpdateTrigger(knex, TableName.LdapGroupMap);
|
||||||
await knex.schema.alterTable(TableName.LdapConfig, (t) => {
|
await knex.schema.alterTable(TableName.LdapConfig, (t) => {
|
||||||
t.dropColumn("groupSearchBase");
|
t.dropColumn("groupSearchBase");
|
||||||
t.dropColumn("groupSearchFilter");
|
t.dropColumn("groupSearchFilter");
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export * from "./incident-contacts";
|
|||||||
export * from "./integration-auths";
|
export * from "./integration-auths";
|
||||||
export * from "./integrations";
|
export * from "./integrations";
|
||||||
export * from "./ldap-configs";
|
export * from "./ldap-configs";
|
||||||
|
export * from "./ldap-group-maps";
|
||||||
export * from "./models";
|
export * from "./models";
|
||||||
export * from "./org-bots";
|
export * from "./org-bots";
|
||||||
export * from "./org-memberships";
|
export * from "./org-memberships";
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// Code generated by automation script, DO NOT EDIT.
|
||||||
|
// Automated by pulling database and generating zod schema
|
||||||
|
// To update. Just run npm run generate:schema
|
||||||
|
// Written by akhilmhdh.
|
||||||
|
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { TImmutableDBKeys } from "./models";
|
||||||
|
|
||||||
|
export const LdapGroupMapsSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
ldapConfigId: z.string().uuid(),
|
||||||
|
ldapGroupCN: z.string(),
|
||||||
|
groupSlug: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TLdapGroupMaps = z.infer<typeof LdapGroupMapsSchema>;
|
||||||
|
export type TLdapGroupMapsInsert = Omit<z.input<typeof LdapGroupMapsSchema>, TImmutableDBKeys>;
|
||||||
|
export type TLdapGroupMapsUpdate = Partial<Omit<z.input<typeof LdapGroupMapsSchema>, TImmutableDBKeys>>;
|
||||||
@@ -60,6 +60,7 @@ export enum TableName {
|
|||||||
SecretRotationOutput = "secret_rotation_outputs",
|
SecretRotationOutput = "secret_rotation_outputs",
|
||||||
SamlConfig = "saml_configs",
|
SamlConfig = "saml_configs",
|
||||||
LdapConfig = "ldap_configs",
|
LdapConfig = "ldap_configs",
|
||||||
|
LdapGroupMap = "ldap_group_maps",
|
||||||
AuditLog = "audit_logs",
|
AuditLog = "audit_logs",
|
||||||
GitAppInstallSession = "git_app_install_sessions",
|
GitAppInstallSession = "git_app_install_sessions",
|
||||||
GitAppOrg = "git_app_org",
|
GitAppOrg = "git_app_org",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import ldapjs from "ldapjs";
|
|||||||
import LdapStrategy from "passport-ldapauth";
|
import LdapStrategy from "passport-ldapauth";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { LdapConfigsSchema } from "@app/db/schemas";
|
import { LdapConfigsSchema, LdapGroupMapsSchema } from "@app/db/schemas";
|
||||||
import { searchGroups } from "@app/ee/services/ldap-config/ldap-fns";
|
import { searchGroups } from "@app/ee/services/ldap-config/ldap-fns";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
@@ -67,6 +67,28 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
try {
|
try {
|
||||||
const ldapConfig = (req as unknown as FastifyRequest).ldapConfig as LDAPConfig;
|
const ldapConfig = (req as unknown as FastifyRequest).ldapConfig as LDAPConfig;
|
||||||
|
|
||||||
|
if (!ldapConfig.groupSearchFilter || !ldapConfig.groupSearchBase) {
|
||||||
|
// If group search values are not provided, proceed directly to LDAP login
|
||||||
|
return await server.services.ldap
|
||||||
|
.ldapLogin({
|
||||||
|
externalId: user.uidNumber,
|
||||||
|
username: user.uid,
|
||||||
|
firstName: user.givenName,
|
||||||
|
lastName: user.sn,
|
||||||
|
emails: user.mail ? [user.mail] : [],
|
||||||
|
relayState: ((req as unknown as FastifyRequest).body as { RelayState?: string }).RelayState,
|
||||||
|
orgId: (req as unknown as FastifyRequest).ldapConfig.organization
|
||||||
|
})
|
||||||
|
.then(({ isUserCompleted, providerAuthToken }) => {
|
||||||
|
cb(null, { isUserCompleted, providerAuthToken });
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
logger.error(err);
|
||||||
|
cb(err, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// query for groups
|
||||||
const ldapClient = ldapjs.createClient({
|
const ldapClient = ldapjs.createClient({
|
||||||
url: ldapConfig.url,
|
url: ldapConfig.url,
|
||||||
bindDN: ldapConfig.bindDN,
|
bindDN: ldapConfig.bindDN,
|
||||||
@@ -85,7 +107,7 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
const searchFilter = groupFilter.replace("{{.Username}}", user.uid).replace("{{.UserDN}}", user.dn);
|
const searchFilter = groupFilter.replace("{{.Username}}", user.uid).replace("{{.UserDN}}", user.dn);
|
||||||
|
|
||||||
searchGroups(ldapClient, searchFilter, ldapConfig.groupSearchBase)
|
searchGroups(ldapClient, searchFilter, ldapConfig.groupSearchBase)
|
||||||
.then(() => {
|
.then((groups) => {
|
||||||
// groups here
|
// groups here
|
||||||
ldapClient.unbind();
|
ldapClient.unbind();
|
||||||
return server.services.ldap.ldapLogin({
|
return server.services.ldap.ldapLogin({
|
||||||
@@ -94,6 +116,7 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
firstName: user.givenName,
|
firstName: user.givenName,
|
||||||
lastName: user.sn,
|
lastName: user.sn,
|
||||||
emails: user.mail ? [user.mail] : [],
|
emails: user.mail ? [user.mail] : [],
|
||||||
|
groups,
|
||||||
relayState: ((req as unknown as FastifyRequest).body as { RelayState?: string }).RelayState,
|
relayState: ((req as unknown as FastifyRequest).body as { RelayState?: string }).RelayState,
|
||||||
orgId: (req as unknown as FastifyRequest).ldapConfig.organization
|
orgId: (req as unknown as FastifyRequest).ldapConfig.organization
|
||||||
});
|
});
|
||||||
@@ -256,4 +279,95 @@ export const registerLdapRouter = async (server: FastifyZodProvider) => {
|
|||||||
return ldap;
|
return ldap;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/config/:configId/group-maps",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
configId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.array(LdapGroupMapsSchema)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const ldapGroupMaps = await server.services.ldap.getLdapGroupMaps({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
ldapConfigId: req.params.configId
|
||||||
|
});
|
||||||
|
return ldapGroupMaps;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/config/:configId/group-maps",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
configId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
ldapGroupCN: z.string().trim(),
|
||||||
|
groupSlug: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: LdapGroupMapsSchema
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const ldapGroupMap = await server.services.ldap.createLdapGroupMap({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
ldapConfigId: req.params.configId,
|
||||||
|
...req.body
|
||||||
|
});
|
||||||
|
return ldapGroupMap;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/config/:configId/group-maps/:groupMapId",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
params: z.object({
|
||||||
|
configId: z.string().trim(),
|
||||||
|
groupMapId: z.string().trim()
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: LdapGroupMapsSchema
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const ldapGroupMap = await server.services.ldap.deleteLdapGroupMap({
|
||||||
|
actor: req.permission.type,
|
||||||
|
actorId: req.permission.id,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
actorAuthMethod: req.permission.authMethod,
|
||||||
|
actorOrgId: req.permission.orgId,
|
||||||
|
ldapConfigId: req.params.configId,
|
||||||
|
ldapGroupMapId: req.params.groupMapId
|
||||||
|
});
|
||||||
|
return ldapGroupMap;
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
|
|
||||||
import { OrgMembershipRole, OrgMembershipStatus, SecretKeyEncoding, TLdapConfigsUpdate } from "@app/db/schemas";
|
import { OrgMembershipRole, OrgMembershipStatus, SecretKeyEncoding, TLdapConfigsUpdate } from "@app/db/schemas";
|
||||||
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import {
|
import {
|
||||||
decryptSymmetric,
|
decryptSymmetric,
|
||||||
@@ -23,15 +24,26 @@ import { TLicenseServiceFactory } from "../license/license-service";
|
|||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "../permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "../permission/permission-service";
|
import { TPermissionServiceFactory } from "../permission/permission-service";
|
||||||
import { TLdapConfigDALFactory } from "./ldap-config-dal";
|
import { TLdapConfigDALFactory } from "./ldap-config-dal";
|
||||||
import { TCreateLdapCfgDTO, TGetLdapCfgDTO, TLdapLoginDTO, TUpdateLdapCfgDTO } from "./ldap-config-types";
|
import {
|
||||||
|
TCreateLdapCfgDTO,
|
||||||
|
TCreateLdapGroupMapDTO,
|
||||||
|
TDeleteLdapGroupMapDTO,
|
||||||
|
TGetLdapCfgDTO,
|
||||||
|
TGetLdapGroupMapsDTO,
|
||||||
|
TLdapLoginDTO,
|
||||||
|
TUpdateLdapCfgDTO
|
||||||
|
} from "./ldap-config-types";
|
||||||
|
import { TLdapGroupMapDALFactory } from "./ldap-group-map-dal";
|
||||||
|
|
||||||
type TLdapConfigServiceFactoryDep = {
|
type TLdapConfigServiceFactoryDep = {
|
||||||
ldapConfigDAL: TLdapConfigDALFactory;
|
ldapConfigDAL: Pick<TLdapConfigDALFactory, "create" | "update" | "findOne">;
|
||||||
|
ldapGroupMapDAL: Pick<TLdapGroupMapDALFactory, "find" | "create" | "delete">;
|
||||||
orgDAL: Pick<
|
orgDAL: Pick<
|
||||||
TOrgDALFactory,
|
TOrgDALFactory,
|
||||||
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" | "findOne" | "updateById"
|
"createMembership" | "updateMembershipById" | "findMembership" | "findOrgById" | "findOne" | "updateById"
|
||||||
>;
|
>;
|
||||||
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
|
orgBotDAL: Pick<TOrgBotDALFactory, "findOne" | "create" | "transaction">;
|
||||||
|
groupDAL: TGroupDALFactory; // TODO: Pick
|
||||||
userDAL: Pick<TUserDALFactory, "create" | "findOne" | "transaction" | "updateById">;
|
userDAL: Pick<TUserDALFactory, "create" | "findOne" | "transaction" | "updateById">;
|
||||||
userAliasDAL: Pick<TUserAliasDALFactory, "create" | "findOne">;
|
userAliasDAL: Pick<TUserAliasDALFactory, "create" | "findOne">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
@@ -42,6 +54,7 @@ export type TLdapConfigServiceFactory = ReturnType<typeof ldapConfigServiceFacto
|
|||||||
|
|
||||||
export const ldapConfigServiceFactory = ({
|
export const ldapConfigServiceFactory = ({
|
||||||
ldapConfigDAL,
|
ldapConfigDAL,
|
||||||
|
ldapGroupMapDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
orgBotDAL,
|
orgBotDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
@@ -406,6 +419,24 @@ export const ldapConfigServiceFactory = ({
|
|||||||
|
|
||||||
const user = await userDAL.findOne({ id: userAlias.userId });
|
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");
|
||||||
|
// }
|
||||||
|
|
||||||
const isUserCompleted = Boolean(user.isAccepted);
|
const isUserCompleted = Boolean(user.isAccepted);
|
||||||
|
|
||||||
const providerAuthToken = jwt.sign(
|
const providerAuthToken = jwt.sign(
|
||||||
@@ -434,6 +465,87 @@ export const ldapConfigServiceFactory = ({
|
|||||||
return { isUserCompleted, providerAuthToken };
|
return { isUserCompleted, providerAuthToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getLdapGroupMaps = async ({
|
||||||
|
ldapConfigId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: TGetLdapGroupMapsDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
|
const ldapConfig = await ldapConfigDAL.findOne({
|
||||||
|
id: ldapConfigId,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
|
||||||
|
|
||||||
|
const groupMaps = await ldapGroupMapDAL.find({
|
||||||
|
ldapConfigId
|
||||||
|
});
|
||||||
|
|
||||||
|
return groupMaps;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createLdapGroupMap = async ({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupCN,
|
||||||
|
groupSlug,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: TCreateLdapGroupMapDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
|
const ldapConfig = await ldapConfigDAL.findOne({
|
||||||
|
id: ldapConfigId,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
|
||||||
|
|
||||||
|
const groupMap = await ldapGroupMapDAL.create({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupCN,
|
||||||
|
groupSlug
|
||||||
|
});
|
||||||
|
|
||||||
|
return groupMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteLdapGroupMap = async ({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupMapId,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
}: TDeleteLdapGroupMapDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
|
const ldapConfig = await ldapConfigDAL.findOne({
|
||||||
|
id: ldapConfigId,
|
||||||
|
orgId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!ldapConfig) throw new BadRequestError({ message: "Failed to find organization LDAP data" });
|
||||||
|
|
||||||
|
const [deletedGroupMap] = await ldapGroupMapDAL.delete({
|
||||||
|
ldapConfigId: ldapConfig.id,
|
||||||
|
id: ldapGroupMapId
|
||||||
|
});
|
||||||
|
|
||||||
|
return deletedGroupMap;
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createLdapCfg,
|
createLdapCfg,
|
||||||
updateLdapCfg,
|
updateLdapCfg,
|
||||||
@@ -441,6 +553,9 @@ export const ldapConfigServiceFactory = ({
|
|||||||
getLdapCfg,
|
getLdapCfg,
|
||||||
// getLdapPassportOpts,
|
// getLdapPassportOpts,
|
||||||
ldapLogin,
|
ldapLogin,
|
||||||
bootLdap
|
bootLdap,
|
||||||
|
getLdapGroupMaps,
|
||||||
|
createLdapGroupMap,
|
||||||
|
deleteLdapGroupMap
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,5 +37,24 @@ export type TLdapLoginDTO = {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
emails: string[];
|
emails: string[];
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
groups?: {
|
||||||
|
dn: string;
|
||||||
|
cn: string;
|
||||||
|
}[];
|
||||||
relayState?: string;
|
relayState?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TGetLdapGroupMapsDTO = {
|
||||||
|
ldapConfigId: string;
|
||||||
|
} & TOrgPermission;
|
||||||
|
|
||||||
|
export type TCreateLdapGroupMapDTO = {
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupCN: string;
|
||||||
|
groupSlug: string;
|
||||||
|
} & TOrgPermission;
|
||||||
|
|
||||||
|
export type TDeleteLdapGroupMapDTO = {
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupMapId: string;
|
||||||
|
} & TOrgPermission;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { TDbClient } from "@app/db";
|
||||||
|
import { TableName } from "@app/db/schemas";
|
||||||
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
|
export type TLdapGroupMapDALFactory = ReturnType<typeof ldapGroupMapDALFactory>;
|
||||||
|
|
||||||
|
export const ldapGroupMapDALFactory = (db: TDbClient) => {
|
||||||
|
const ldapGroupMapOrm = ormify(db, TableName.LdapGroupMap);
|
||||||
|
|
||||||
|
return { ...ldapGroupMapOrm };
|
||||||
|
};
|
||||||
@@ -18,6 +18,7 @@ import { identityProjectAdditionalPrivilegeDALFactory } from "@app/ee/services/i
|
|||||||
import { identityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
|
import { identityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
|
||||||
import { ldapConfigDALFactory } from "@app/ee/services/ldap-config/ldap-config-dal";
|
import { ldapConfigDALFactory } from "@app/ee/services/ldap-config/ldap-config-dal";
|
||||||
import { ldapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
import { ldapConfigServiceFactory } from "@app/ee/services/ldap-config/ldap-config-service";
|
||||||
|
import { ldapGroupMapDALFactory } from "@app/ee/services/ldap-config/ldap-group-map-dal";
|
||||||
import { licenseDALFactory } from "@app/ee/services/license/license-dal";
|
import { licenseDALFactory } from "@app/ee/services/license/license-dal";
|
||||||
import { licenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { licenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { permissionDALFactory } from "@app/ee/services/permission/permission-dal";
|
import { permissionDALFactory } from "@app/ee/services/permission/permission-dal";
|
||||||
@@ -200,6 +201,7 @@ export const registerRoutes = async (
|
|||||||
const samlConfigDAL = samlConfigDALFactory(db);
|
const samlConfigDAL = samlConfigDALFactory(db);
|
||||||
const scimDAL = scimDALFactory(db);
|
const scimDAL = scimDALFactory(db);
|
||||||
const ldapConfigDAL = ldapConfigDALFactory(db);
|
const ldapConfigDAL = ldapConfigDALFactory(db);
|
||||||
|
const ldapGroupMapDAL = ldapGroupMapDALFactory(db);
|
||||||
const sapApproverDAL = secretApprovalPolicyApproverDALFactory(db);
|
const sapApproverDAL = secretApprovalPolicyApproverDALFactory(db);
|
||||||
const secretApprovalPolicyDAL = secretApprovalPolicyDALFactory(db);
|
const secretApprovalPolicyDAL = secretApprovalPolicyDALFactory(db);
|
||||||
const secretApprovalRequestDAL = secretApprovalRequestDALFactory(db);
|
const secretApprovalRequestDAL = secretApprovalRequestDALFactory(db);
|
||||||
@@ -300,8 +302,10 @@ export const registerRoutes = async (
|
|||||||
|
|
||||||
const ldapService = ldapConfigServiceFactory({
|
const ldapService = ldapConfigServiceFactory({
|
||||||
ldapConfigDAL,
|
ldapConfigDAL,
|
||||||
|
ldapGroupMapDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
orgBotDAL,
|
orgBotDAL,
|
||||||
|
groupDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
userAliasDAL,
|
userAliasDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
export { useCreateLDAPConfig, useUpdateLDAPConfig } from "./mutations";
|
export {
|
||||||
export { useGetLDAPConfig } from "./queries";
|
useCreateLDAPConfig,
|
||||||
|
useCreateLDAPGroupMapping,
|
||||||
|
useDeleteLDAPGroupMapping,
|
||||||
|
useUpdateLDAPConfig} from "./mutations";
|
||||||
|
export { useGetLDAPConfig, useGetLDAPGroupMaps } from "./queries";
|
||||||
|
|||||||
@@ -91,3 +91,48 @@ export const useUpdateLDAPConfig = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCreateLDAPGroupMapping = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupCN,
|
||||||
|
groupSlug
|
||||||
|
}: {
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupCN: string;
|
||||||
|
groupSlug: string;
|
||||||
|
}) => {
|
||||||
|
const { data } = await apiRequest.post(`/api/v1/ldap/config/${ldapConfigId}/group-maps`, {
|
||||||
|
ldapGroupCN,
|
||||||
|
groupSlug
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
onSuccess(_, { ldapConfigId }) {
|
||||||
|
queryClient.invalidateQueries(ldapConfigKeys.getLDAPGroupMaps(ldapConfigId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDeleteLDAPGroupMapping = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async ({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupMapId
|
||||||
|
}: {
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupMapId: string;
|
||||||
|
}) => {
|
||||||
|
const { data } = await apiRequest.delete(
|
||||||
|
`/api/v1/ldap/config/${ldapConfigId}/group-maps/${ldapGroupMapId}`
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
onSuccess(_, { ldapConfigId }) {
|
||||||
|
queryClient.invalidateQueries(ldapConfigKeys.getLDAPGroupMaps(ldapConfigId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -2,8 +2,11 @@ import { useQuery } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { apiRequest } from "@app/config/request";
|
import { apiRequest } from "@app/config/request";
|
||||||
|
|
||||||
|
import { LDAPGroupMap } from "./types";
|
||||||
|
|
||||||
export const ldapConfigKeys = {
|
export const ldapConfigKeys = {
|
||||||
getLDAPConfig: (orgId: string) => [{ orgId }, "organization-ldap"] as const
|
getLDAPConfig: (orgId: string) => [{ orgId }, "organization-ldap"] as const,
|
||||||
|
getLDAPGroupMaps: (ldapConfigId: string) => [{ ldapConfigId }, "ldap-group-maps"] as const
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGetLDAPConfig = (organizationId: string) => {
|
export const useGetLDAPConfig = (organizationId: string) => {
|
||||||
@@ -17,3 +20,19 @@ export const useGetLDAPConfig = (organizationId: string) => {
|
|||||||
enabled: true
|
enabled: true
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useGetLDAPGroupMaps = (ldapConfigId: string) => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ldapConfigKeys.getLDAPGroupMaps(ldapConfigId),
|
||||||
|
queryFn: async () => {
|
||||||
|
if (!ldapConfigId) return [];
|
||||||
|
|
||||||
|
const { data } = await apiRequest.get<LDAPGroupMap[]>(
|
||||||
|
`/api/v1/ldap/config/${ldapConfigId}/group-maps`
|
||||||
|
);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
enabled: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export type LDAPGroupMap = {
|
||||||
|
id: string;
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupCN: string;
|
||||||
|
groupSlug: string;
|
||||||
|
};
|
||||||
+238
@@ -0,0 +1,238 @@
|
|||||||
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
import { faUsers, faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { createNotification } from "@app/components/notifications";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
DeleteActionModal,
|
||||||
|
EmptyState,
|
||||||
|
FormControl,
|
||||||
|
IconButton,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalContent,
|
||||||
|
Table,
|
||||||
|
TableContainer,
|
||||||
|
TableSkeleton,
|
||||||
|
TBody,
|
||||||
|
Td,
|
||||||
|
Th,
|
||||||
|
THead,
|
||||||
|
Tr} from "@app/components/v2";
|
||||||
|
import { useOrganization } from "@app/context";
|
||||||
|
import {
|
||||||
|
useCreateLDAPGroupMapping,
|
||||||
|
useDeleteLDAPGroupMapping,
|
||||||
|
useGetLDAPConfig,
|
||||||
|
useGetLDAPGroupMaps} from "@app/hooks/api";
|
||||||
|
import { UsePopUpState } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
ldapGroupCN: z.string().min(1, "LDAP Group CN is required"),
|
||||||
|
groupSlug: z.string().min(1, "Group Slug is required")
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TFormData = z.infer<typeof schema>;
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
popUp: UsePopUpState<["ldapGroupMap", "deleteLdapGroupMap"]>;
|
||||||
|
handlePopUpOpen: (
|
||||||
|
popUpName: keyof UsePopUpState<["deleteLdapGroupMap"]>,
|
||||||
|
data?: {
|
||||||
|
ldapGroupMapId: string;
|
||||||
|
ldapGroupCN: string;
|
||||||
|
}
|
||||||
|
) => void;
|
||||||
|
handlePopUpToggle: (
|
||||||
|
popUpName: keyof UsePopUpState<["ldapGroupMap", "deleteLdapGroupMap"]>,
|
||||||
|
state?: boolean
|
||||||
|
) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LDAPGroupMapModal = ({ popUp, handlePopUpOpen, handlePopUpToggle }: Props) => {
|
||||||
|
const { currentOrg } = useOrganization();
|
||||||
|
|
||||||
|
const { data: ldapConfig } = useGetLDAPConfig(currentOrg?.id ?? "");
|
||||||
|
const { data: groupMaps, isLoading } = useGetLDAPGroupMaps(ldapConfig?.id ?? "");
|
||||||
|
const { mutateAsync: createLDAPGroupMapping, isLoading: createIsLoading } =
|
||||||
|
useCreateLDAPGroupMapping();
|
||||||
|
const { mutateAsync: deleteLDAPGroupMapping } = useDeleteLDAPGroupMapping();
|
||||||
|
|
||||||
|
const { control, handleSubmit, reset } = useForm<TFormData>({
|
||||||
|
resolver: zodResolver(schema),
|
||||||
|
defaultValues: {
|
||||||
|
ldapGroupCN: "",
|
||||||
|
groupSlug: ""
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onFormSubmit = async ({ groupSlug, ldapGroupCN }: TFormData) => {
|
||||||
|
try {
|
||||||
|
if (!ldapConfig) return;
|
||||||
|
|
||||||
|
await createLDAPGroupMapping({
|
||||||
|
ldapConfigId: ldapConfig.id,
|
||||||
|
groupSlug,
|
||||||
|
ldapGroupCN
|
||||||
|
});
|
||||||
|
|
||||||
|
reset();
|
||||||
|
|
||||||
|
createNotification({
|
||||||
|
text: `Successfully added LDAP group mapping for ${ldapGroupCN}`,
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
createNotification({
|
||||||
|
text: `Failed to add LDAP group mapping for ${ldapGroupCN}`,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onDeleteGroupMapSubmit = async ({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupMapId,
|
||||||
|
ldapGroupCN
|
||||||
|
}: {
|
||||||
|
ldapConfigId: string;
|
||||||
|
ldapGroupMapId: string;
|
||||||
|
ldapGroupCN: string;
|
||||||
|
}) => {
|
||||||
|
try {
|
||||||
|
await deleteLDAPGroupMapping({
|
||||||
|
ldapConfigId,
|
||||||
|
ldapGroupMapId
|
||||||
|
});
|
||||||
|
|
||||||
|
handlePopUpToggle("deleteLdapGroupMap", false);
|
||||||
|
|
||||||
|
createNotification({
|
||||||
|
text: `Successfully deleted LDAP group mapping ${ldapGroupCN}`,
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
createNotification({
|
||||||
|
text: `Failed to delete LDAP group mapping ${ldapGroupCN}`,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={popUp?.ldapGroupMap?.isOpen}
|
||||||
|
onOpenChange={(isOpen) => {
|
||||||
|
handlePopUpToggle("ldapGroupMap", isOpen);
|
||||||
|
reset();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ModalContent title="Manage LDAP Group Mappings">
|
||||||
|
<h2 className="mb-4">New Group Mapping</h2>
|
||||||
|
<form onSubmit={handleSubmit(onFormSubmit)} className="mb-8">
|
||||||
|
<div className="flex">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="ldapGroupCN"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="LDAP Group CN"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="Engineering" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="groupSlug"
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
label="Group Slug"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error)}
|
||||||
|
className="ml-4"
|
||||||
|
>
|
||||||
|
<div className="flex">
|
||||||
|
<Input {...field} placeholder="engineering" />
|
||||||
|
<Button className="ml-4" size="sm" type="submit" isLoading={createIsLoading}>
|
||||||
|
Add mapping
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<h2 className="mb-4">Group Mappings</h2>
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<THead>
|
||||||
|
<Tr>
|
||||||
|
<Th>LDAP Group CN</Th>
|
||||||
|
<Th>Group Slug</Th>
|
||||||
|
<Th className="w-5" />
|
||||||
|
</Tr>
|
||||||
|
</THead>
|
||||||
|
<TBody>
|
||||||
|
{isLoading && <TableSkeleton columns={3} innerKey="ldap-group-maps" />}
|
||||||
|
{!isLoading &&
|
||||||
|
groupMaps?.map(({ id, ldapGroupCN, groupSlug }) => {
|
||||||
|
return (
|
||||||
|
<Tr className="h-10 items-center" key={`ldap-group-map-${id}`}>
|
||||||
|
<Td>{ldapGroupCN}</Td>
|
||||||
|
<Td>{groupSlug}</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
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
import { useCreateLDAPConfig, useGetLDAPConfig, useUpdateLDAPConfig } from "@app/hooks/api";
|
import { useCreateLDAPConfig, useGetLDAPConfig, useUpdateLDAPConfig } from "@app/hooks/api";
|
||||||
import { usePopUp } from "@app/hooks/usePopUp";
|
import { usePopUp } from "@app/hooks/usePopUp";
|
||||||
|
|
||||||
|
import { LDAPGroupMapModal } from "./LDAPGroupMapModal";
|
||||||
import { LDAPModal } from "./LDAPModal";
|
import { LDAPModal } from "./LDAPModal";
|
||||||
|
|
||||||
export const OrgLDAPSection = (): JSX.Element => {
|
export const OrgLDAPSection = (): JSX.Element => {
|
||||||
@@ -21,6 +22,8 @@ export const OrgLDAPSection = (): JSX.Element => {
|
|||||||
const { mutateAsync } = useUpdateLDAPConfig();
|
const { mutateAsync } = useUpdateLDAPConfig();
|
||||||
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([
|
||||||
"addLDAP",
|
"addLDAP",
|
||||||
|
"ldapGroupMap",
|
||||||
|
"deleteLdapGroupMap",
|
||||||
"upgradePlan"
|
"upgradePlan"
|
||||||
] as const);
|
] as const);
|
||||||
|
|
||||||
@@ -79,6 +82,16 @@ export const OrgLDAPSection = (): JSX.Element => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openLDAPGroupMapModal = () => {
|
||||||
|
console.log("openLDAPGroupMapModal sub: ", subscription);
|
||||||
|
if (!subscription?.ldap) {
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePopUpOpen("ldapGroupMap");
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<hr className="border-mineshaft-600" />
|
<hr className="border-mineshaft-600" />
|
||||||
@@ -95,6 +108,25 @@ export const OrgLDAPSection = (): JSX.Element => {
|
|||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-mineshaft-300">Manage LDAP authentication configuration</p>
|
<p className="text-sm text-mineshaft-300">Manage LDAP authentication configuration</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="py-4">
|
||||||
|
<div className="mb-2 flex items-center justify-between">
|
||||||
|
<h2 className="text-md text-mineshaft-100">LDAP Group Mappings</h2>
|
||||||
|
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Ldap}>
|
||||||
|
{(isAllowed) => (
|
||||||
|
<Button
|
||||||
|
onClick={openLDAPGroupMapModal}
|
||||||
|
colorSchema="secondary"
|
||||||
|
isDisabled={!isAllowed}
|
||||||
|
>
|
||||||
|
Manage
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</OrgPermissionCan>
|
||||||
|
</div>
|
||||||
|
<p className="text-sm text-mineshaft-300">
|
||||||
|
Manage how LDAP groups are mapped to internal groups in Infisical
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="py-4">
|
<div className="py-4">
|
||||||
<div className="mb-2 flex items-center justify-between">
|
<div className="mb-2 flex items-center justify-between">
|
||||||
@@ -122,6 +154,11 @@ export const OrgLDAPSection = (): JSX.Element => {
|
|||||||
handlePopUpClose={handlePopUpClose}
|
handlePopUpClose={handlePopUpClose}
|
||||||
handlePopUpToggle={handlePopUpToggle}
|
handlePopUpToggle={handlePopUpToggle}
|
||||||
/>
|
/>
|
||||||
|
<LDAPGroupMapModal
|
||||||
|
popUp={popUp}
|
||||||
|
handlePopUpOpen={handlePopUpOpen}
|
||||||
|
handlePopUpToggle={handlePopUpToggle}
|
||||||
|
/>
|
||||||
<UpgradePlanModal
|
<UpgradePlanModal
|
||||||
isOpen={popUp.upgradePlan.isOpen}
|
isOpen={popUp.upgradePlan.isOpen}
|
||||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
||||||
|
|||||||
Reference in New Issue
Block a user