Merge pull request #2138 from Infisical/further-scim-smoothening

Further SCIM Smoothening
This commit is contained in:
BlackMagiq
2024-07-17 18:04:25 +07:00
committed by GitHub
3 changed files with 97 additions and 33 deletions
+7 -2
View File
@@ -350,7 +350,12 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
schemas: z.array(z.string()), schemas: z.array(z.string()),
id: z.string().trim(), id: z.string().trim(),
displayName: z.string().trim(), displayName: z.string().trim(),
members: z.array(z.any()).length(0), members: z.array(
z.object({
value: z.string(),
display: z.string()
})
),
meta: z.object({ meta: z.object({
resourceType: z.string().trim() resourceType: z.string().trim()
}) })
@@ -423,7 +428,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => {
displayName: z.string().trim(), displayName: z.string().trim(),
members: z.array( members: z.array(
z.object({ z.object({
value: z.string(), // infisical orgMembershipId value: z.string(),
display: z.string() display: z.string()
}) })
) )
@@ -162,17 +162,50 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
} }
}; };
const findUserGroupMembershipsInOrg = async (userId: string, orgId: string) => { const findGroupMembershipsByUserIdInOrg = async (userId: string, orgId: string) => {
try { try {
const docs = await db const docs = await db
.replicaNode()(TableName.UserGroupMembership) .replicaNode()(TableName.UserGroupMembership)
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`) .join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
.join(TableName.OrgMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.OrgMembership}.userId`)
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
.where(`${TableName.UserGroupMembership}.userId`, userId) .where(`${TableName.UserGroupMembership}.userId`, userId)
.where(`${TableName.Groups}.orgId`, orgId); .where(`${TableName.Groups}.orgId`, orgId)
.select(
db.ref("id").withSchema(TableName.UserGroupMembership),
db.ref("groupId").withSchema(TableName.UserGroupMembership),
db.ref("name").withSchema(TableName.Groups).as("groupName"),
db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"),
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
db.ref("lastName").withSchema(TableName.Users).as("lastName")
);
return docs; return docs;
} catch (error) { } catch (error) {
throw new DatabaseError({ error, name: "findTest" }); throw new DatabaseError({ error, name: "Find group memberships by user id in org" });
}
};
const findGroupMembershipsByGroupIdInOrg = async (groupId: string, orgId: string) => {
try {
const docs = await db
.replicaNode()(TableName.UserGroupMembership)
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
.join(TableName.OrgMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.OrgMembership}.userId`)
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
.where(`${TableName.Groups}.id`, groupId)
.where(`${TableName.Groups}.orgId`, orgId)
.select(
db.ref("id").withSchema(TableName.UserGroupMembership),
db.ref("groupId").withSchema(TableName.UserGroupMembership),
db.ref("name").withSchema(TableName.Groups).as("groupName"),
db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"),
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
db.ref("lastName").withSchema(TableName.Users).as("lastName")
);
return docs;
} catch (error) {
throw new DatabaseError({ error, name: "Find group memberships by group id in org" });
} }
}; };
@@ -182,6 +215,7 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
findUserGroupMembershipsInProject, findUserGroupMembershipsInProject,
findGroupMembersNotInProject, findGroupMembersNotInProject,
deletePendingUserGroupMembershipsByUserIds, deletePendingUserGroupMembershipsByUserIds,
findUserGroupMembershipsInOrg findGroupMembershipsByUserIdInOrg,
findGroupMembershipsByGroupIdInOrg
}; };
}; };
+52 -27
View File
@@ -9,6 +9,7 @@ import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-grou
import { TScimDALFactory } from "@app/ee/services/scim/scim-dal"; import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
import { getConfig } from "@app/lib/config/env"; import { getConfig } from "@app/lib/config/env";
import { BadRequestError, ScimRequestError, UnauthorizedError } from "@app/lib/errors"; import { BadRequestError, ScimRequestError, UnauthorizedError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TOrgPermission } from "@app/lib/types"; import { TOrgPermission } from "@app/lib/types";
import { AuthTokenType } from "@app/services/auth/auth-type"; import { AuthTokenType } from "@app/services/auth/auth-type";
@@ -51,6 +52,7 @@ import {
TListScimUsers, TListScimUsers,
TListScimUsersDTO, TListScimUsersDTO,
TReplaceScimUserDTO, TReplaceScimUserDTO,
TScimGroup,
TScimTokenJwtPayload, TScimTokenJwtPayload,
TUpdateScimGroupNamePatchDTO, TUpdateScimGroupNamePatchDTO,
TUpdateScimGroupNamePutDTO, TUpdateScimGroupNamePutDTO,
@@ -83,7 +85,8 @@ type TScimServiceFactoryDep = {
| "insertMany" | "insertMany"
| "filterProjectsByUserMembership" | "filterProjectsByUserMembership"
| "delete" | "delete"
| "findUserGroupMembershipsInOrg" | "findGroupMembershipsByUserIdInOrg"
| "findGroupMembershipsByGroupIdInOrg"
>; >;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">; projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">; projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
@@ -252,7 +255,10 @@ export const scimServiceFactory = ({
status: 403 status: 403
}); });
const groupMembershipsInOrg = await userGroupMembershipDAL.findUserGroupMembershipsInOrg(membership.userId, orgId); const groupMembershipsInOrg = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg(
membership.userId,
orgId
);
return buildScimUser({ return buildScimUser({
orgMembershipId: membership.id, orgMembershipId: membership.id,
@@ -263,7 +269,7 @@ export const scimServiceFactory = ({
active: membership.isActive, active: membership.isActive,
groups: groupMembershipsInOrg.map((group) => ({ groups: groupMembershipsInOrg.map((group) => ({
value: group.groupId, value: group.groupId,
display: group.name display: group.groupName
})) }))
}); });
}; };
@@ -509,7 +515,10 @@ export const scimServiceFactory = ({
isActive: active isActive: active
}); });
const groupMembershipsInOrg = await userGroupMembershipDAL.findUserGroupMembershipsInOrg(membership.userId, orgId); const groupMembershipsInOrg = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg(
membership.userId,
orgId
);
return buildScimUser({ return buildScimUser({
orgMembershipId: membership.id, orgMembershipId: membership.id,
@@ -520,7 +529,7 @@ export const scimServiceFactory = ({
active, active,
groups: groupMembershipsInOrg.map((group) => ({ groups: groupMembershipsInOrg.map((group) => ({
value: group.groupId, value: group.groupId,
display: group.name display: group.groupName
})) }))
}); });
}; };
@@ -589,13 +598,20 @@ export const scimServiceFactory = ({
} }
); );
const scimGroups = groups.map((group) => const scimGroups: TScimGroup[] = [];
buildScimGroup({
for await (const group of groups) {
const members = await userGroupMembershipDAL.findGroupMembershipsByGroupIdInOrg(group.id, orgId);
const scimGroup = buildScimGroup({
groupId: group.id, groupId: group.id,
name: group.name, name: group.name,
members: [] // does this need to be populated? members: members.map((member) => ({
}) value: member.orgMembershipId,
); display: `${member.firstName ?? ""} ${member.lastName ?? ""}`
}))
});
scimGroups.push(scimGroup);
}
return buildScimGroupList({ return buildScimGroupList({
scimGroups, scimGroups,
@@ -872,23 +888,27 @@ export const scimServiceFactory = ({
break; break;
} }
case "add": { case "add": {
const orgMemberships = await orgMembershipDAL.find({ try {
$in: { const orgMemberships = await orgMembershipDAL.find({
id: operation.value.map((member) => member.value) $in: {
} id: operation.value.map((member) => member.value)
}); }
});
await addUsersToGroupByUserIds({ await addUsersToGroupByUserIds({
group, group,
userIds: orgMemberships.map((membership) => membership.userId as string), userIds: orgMemberships.map((membership) => membership.userId as string),
userDAL, userDAL,
userGroupMembershipDAL, userGroupMembershipDAL,
orgDAL, orgDAL,
groupProjectDAL, groupProjectDAL,
projectKeyDAL, projectKeyDAL,
projectDAL, projectDAL,
projectBotDAL projectBotDAL
}); });
} catch {
logger.info("Repeat SCIM user-group add operation");
}
break; break;
} }
@@ -916,10 +936,15 @@ export const scimServiceFactory = ({
} }
} }
const members = await userGroupMembershipDAL.findGroupMembershipsByGroupIdInOrg(group.id, orgId);
return buildScimGroup({ return buildScimGroup({
groupId: group.id, groupId: group.id,
name: group.name, name: group.name,
members: [] members: members.map((member) => ({
value: member.orgMembershipId,
display: `${member.firstName ?? ""} ${member.lastName ?? ""}`
}))
}); });
}; };