mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 14:27:30 +00:00
Merge branch 'Infisical:main' into main
This commit is contained in:
@@ -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
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 ?? ""}`
|
||||||
|
}))
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,30 @@ This guide walks through how you can use these paid features on a self hosted in
|
|||||||
</Step>
|
</Step>
|
||||||
<Step title="Activate the license">
|
<Step title="Activate the license">
|
||||||
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.
|
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.
|
|
||||||
|
|
||||||
<Note>
|
|
||||||
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.
|
<Tabs>
|
||||||
</Note>
|
<Tab title="Regular License">
|
||||||
|
- 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`
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
Ensure that your firewall or network settings allow outbound connections to these IP addresses to avoid any issues with license validation.
|
||||||
|
</Note>
|
||||||
|
</Tab>
|
||||||
|
<Tab title="Offline License">
|
||||||
|
- Assign the issued license key to the `LICENSE_KEY_OFFLINE` environment variable in your Infisical instance.
|
||||||
|
|
||||||
|
<Note>
|
||||||
|
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.
|
||||||
|
</Note>
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
Once your instance starts up, the license key will be validated and you’ll be able to use the paid features.
|
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.
|
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.
|
||||||
</Step>
|
</Step>
|
||||||
</Steps>
|
</Steps>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user