From 22b954b65778cf906ec462acba19cb7850808376 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Wed, 17 Jul 2024 11:24:57 +0700 Subject: [PATCH 1/3] Further smoothen scim --- backend/src/ee/routes/v1/scim-router.ts | 9 ++- .../group/user-group-membership-dal.ts | 42 +++++++++- backend/src/ee/services/scim/scim-service.ts | 79 ++++++++++++------- 3 files changed, 97 insertions(+), 33 deletions(-) diff --git a/backend/src/ee/routes/v1/scim-router.ts b/backend/src/ee/routes/v1/scim-router.ts index 88a1df457..e3456c70a 100644 --- a/backend/src/ee/routes/v1/scim-router.ts +++ b/backend/src/ee/routes/v1/scim-router.ts @@ -350,7 +350,12 @@ export const registerScimRouter = async (server: FastifyZodProvider) => { schemas: z.array(z.string()), id: 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({ resourceType: z.string().trim() }) @@ -423,7 +428,7 @@ export const registerScimRouter = async (server: FastifyZodProvider) => { displayName: z.string().trim(), members: z.array( z.object({ - value: z.string(), // infisical orgMembershipId + value: z.string(), display: z.string() }) ) diff --git a/backend/src/ee/services/group/user-group-membership-dal.ts b/backend/src/ee/services/group/user-group-membership-dal.ts index 64983d24f..b53f59320 100644 --- a/backend/src/ee/services/group/user-group-membership-dal.ts +++ b/backend/src/ee/services/group/user-group-membership-dal.ts @@ -162,17 +162,50 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => { } }; - const findUserGroupMembershipsInOrg = async (userId: string, orgId: string) => { + const findGroupMembershipsByUserIdInOrg = async (userId: 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.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; } 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 user id in org" }); } }; @@ -182,6 +215,7 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => { findUserGroupMembershipsInProject, findGroupMembersNotInProject, deletePendingUserGroupMembershipsByUserIds, - findUserGroupMembershipsInOrg + findGroupMembershipsByUserIdInOrg, + findGroupMembershipsByGroupIdInOrg }; }; diff --git a/backend/src/ee/services/scim/scim-service.ts b/backend/src/ee/services/scim/scim-service.ts index 2f39e9168..5787924dd 100644 --- a/backend/src/ee/services/scim/scim-service.ts +++ b/backend/src/ee/services/scim/scim-service.ts @@ -9,6 +9,7 @@ import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-grou import { TScimDALFactory } from "@app/ee/services/scim/scim-dal"; import { getConfig } from "@app/lib/config/env"; import { BadRequestError, ScimRequestError, UnauthorizedError } from "@app/lib/errors"; +import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { TOrgPermission } from "@app/lib/types"; import { AuthTokenType } from "@app/services/auth/auth-type"; @@ -51,6 +52,7 @@ import { TListScimUsers, TListScimUsersDTO, TReplaceScimUserDTO, + TScimGroup, TScimTokenJwtPayload, TUpdateScimGroupNamePatchDTO, TUpdateScimGroupNamePutDTO, @@ -83,7 +85,8 @@ type TScimServiceFactoryDep = { | "insertMany" | "filterProjectsByUserMembership" | "delete" - | "findUserGroupMembershipsInOrg" + | "findGroupMembershipsByUserIdInOrg" + | "findGroupMembershipsByGroupIdInOrg" >; projectKeyDAL: Pick; projectBotDAL: Pick; @@ -252,7 +255,10 @@ export const scimServiceFactory = ({ status: 403 }); - const groupMembershipsInOrg = await userGroupMembershipDAL.findUserGroupMembershipsInOrg(membership.userId, orgId); + const groupMembershipsInOrg = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg( + membership.userId, + orgId + ); return buildScimUser({ orgMembershipId: membership.id, @@ -263,7 +269,7 @@ export const scimServiceFactory = ({ active: membership.isActive, groups: groupMembershipsInOrg.map((group) => ({ value: group.groupId, - display: group.name + display: group.groupName })) }); }; @@ -509,7 +515,10 @@ export const scimServiceFactory = ({ isActive: active }); - const groupMembershipsInOrg = await userGroupMembershipDAL.findUserGroupMembershipsInOrg(membership.userId, orgId); + const groupMembershipsInOrg = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg( + membership.userId, + orgId + ); return buildScimUser({ orgMembershipId: membership.id, @@ -520,7 +529,7 @@ export const scimServiceFactory = ({ active, groups: groupMembershipsInOrg.map((group) => ({ value: group.groupId, - display: group.name + display: group.groupName })) }); }; @@ -589,13 +598,20 @@ export const scimServiceFactory = ({ } ); - const scimGroups = groups.map((group) => - buildScimGroup({ + const scimGroups: TScimGroup[] = []; + + for await (const group of groups) { + const members = await userGroupMembershipDAL.findGroupMembershipsByGroupIdInOrg(group.id, orgId); + const scimGroup = buildScimGroup({ groupId: group.id, 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({ scimGroups, @@ -872,23 +888,27 @@ export const scimServiceFactory = ({ break; } case "add": { - const orgMemberships = await orgMembershipDAL.find({ - $in: { - id: operation.value.map((member) => member.value) - } - }); + try { + const orgMemberships = await orgMembershipDAL.find({ + $in: { + id: operation.value.map((member) => member.value) + } + }); - await addUsersToGroupByUserIds({ - group, - userIds: orgMemberships.map((membership) => membership.userId as string), - userDAL, - userGroupMembershipDAL, - orgDAL, - groupProjectDAL, - projectKeyDAL, - projectDAL, - projectBotDAL - }); + await addUsersToGroupByUserIds({ + group, + userIds: orgMemberships.map((membership) => membership.userId as string), + userDAL, + userGroupMembershipDAL, + orgDAL, + groupProjectDAL, + projectKeyDAL, + projectDAL, + projectBotDAL + }); + } catch { + logger.info("Repeat SCIM user-group add operation"); + } break; } @@ -916,10 +936,15 @@ export const scimServiceFactory = ({ } } + const members = await userGroupMembershipDAL.findGroupMembershipsByGroupIdInOrg(group.id, orgId); + return buildScimGroup({ groupId: group.id, name: group.name, - members: [] + members: members.map((member) => ({ + value: member.orgMembershipId, + display: `${member.firstName ?? ""} ${member.lastName ?? ""}` + })) }); }; From 1ae375188b6cde4e5a28ed08a73f9f27e14d1098 Mon Sep 17 00:00:00 2001 From: Tuan Dang Date: Wed, 17 Jul 2024 11:27:09 +0700 Subject: [PATCH 2/3] Correct database error message --- backend/src/ee/services/group/user-group-membership-dal.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/ee/services/group/user-group-membership-dal.ts b/backend/src/ee/services/group/user-group-membership-dal.ts index b53f59320..cadbbdc36 100644 --- a/backend/src/ee/services/group/user-group-membership-dal.ts +++ b/backend/src/ee/services/group/user-group-membership-dal.ts @@ -205,7 +205,7 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => { ); return docs; } catch (error) { - throw new DatabaseError({ error, name: "Find group memberships by user id in org" }); + throw new DatabaseError({ error, name: "Find group memberships by group id in org" }); } }; From 7e9c846ba38b6362ab41b452cb86d4cbfd11aeee Mon Sep 17 00:00:00 2001 From: Maidul Islam Date: Wed, 17 Jul 2024 19:11:55 -0400 Subject: [PATCH 3/3] add ips for whitelisting --- docs/self-hosting/ee.mdx | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/docs/self-hosting/ee.mdx b/docs/self-hosting/ee.mdx index a72bad908..d77510c11 100644 --- a/docs/self-hosting/ee.mdx +++ b/docs/self-hosting/ee.mdx @@ -15,15 +15,30 @@ This guide walks through how you can use these paid features on a self hosted in Depending on whether or not the environment where Infisical is deployed has internet access, you may be issued a regular license or an offline license. - - - If using a regular license, you should set the value of the environment variable `LICENSE_KEY` in Infisical to the issued license key. - - If using an offline license, you should set the value of the environment variable `LICENSE_KEY_OFFLINE` in Infisical to the issued license key. - - How you set the environment variable will depend on the deployment method you used. Please refer to the documentation of your deployment method for specific instructions. - + + + + - Assign the issued license key to the `LICENSE_KEY` environment variable in your Infisical instance. + + - Your Infisical instance will need to communicate with the Infisical license server to validate the license key. + If you want to limit outgoing connections only to the Infisical license server, you can use the following IP addresses: `13.248.249.247` and `35.71.190.59` + + + Ensure that your firewall or network settings allow outbound connections to these IP addresses to avoid any issues with license validation. + + + + - Assign the issued license key to the `LICENSE_KEY_OFFLINE` environment variable in your Infisical instance. + + + How you set the environment variable will depend on the deployment method you used. Please refer to the documentation of your deployment method for specific instructions. + + + Once your instance starts up, the license key will be validated and you’ll be able to use the paid features. However, when the license expires, Infisical will continue to run, but EE features will be disabled until the license is renewed or a new one is purchased. +