mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 23:47:06 +00:00
Fix merge conflicts
This commit is contained in:
@@ -31,8 +31,18 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUser}.id`,
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.Users}.id`, `${TableName.SshHostLoginUserMapping}.userId`)
|
||||
.leftJoin(
|
||||
TableName.UserGroupMembership,
|
||||
`${TableName.UserGroupMembership}.groupId`,
|
||||
`${TableName.SshHostLoginUserMapping}.groupId`
|
||||
)
|
||||
.whereIn(`${TableName.SshHost}.projectId`, projectIds)
|
||||
.andWhere(`${TableName.SshHostLoginUserMapping}.userId`, userId)
|
||||
.andWhere((bd) => {
|
||||
void bd
|
||||
.where(`${TableName.SshHostLoginUserMapping}.userId`, userId)
|
||||
.orWhere(`${TableName.UserGroupMembership}.userId`, userId);
|
||||
})
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.SshHost).as("sshHostId"),
|
||||
db.ref("projectId").withSchema(TableName.SshHost),
|
||||
@@ -58,8 +68,17 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.join(TableName.SshHost, `${TableName.SshHostGroupMembership}.sshHostId`, `${TableName.SshHost}.id`)
|
||||
.leftJoin(
|
||||
TableName.UserGroupMembership,
|
||||
`${TableName.UserGroupMembership}.groupId`,
|
||||
`${TableName.SshHostLoginUserMapping}.groupId`
|
||||
)
|
||||
.whereIn(`${TableName.SshHost}.projectId`, projectIds)
|
||||
.andWhere(`${TableName.SshHostLoginUserMapping}.userId`, userId)
|
||||
.andWhere((bd) => {
|
||||
void bd
|
||||
.where(`${TableName.SshHostLoginUserMapping}.userId`, userId)
|
||||
.orWhere(`${TableName.UserGroupMembership}.userId`, userId);
|
||||
})
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.SshHost).as("sshHostId"),
|
||||
db.ref("projectId").withSchema(TableName.SshHost),
|
||||
@@ -133,6 +152,7 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.SshHostLoginUserMapping}.userId`, `${TableName.Users}.id`)
|
||||
.leftJoin(TableName.Groups, `${TableName.SshHostLoginUserMapping}.groupId`, `${TableName.Groups}.id`)
|
||||
.where(`${TableName.SshHost}.projectId`, projectId)
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.SshHost).as("sshHostId"),
|
||||
@@ -144,6 +164,7 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
db.ref("loginUser").withSchema(TableName.SshHostLoginUser),
|
||||
db.ref("username").withSchema(TableName.Users),
|
||||
db.ref("userId").withSchema(TableName.SshHostLoginUserMapping),
|
||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug"),
|
||||
db.ref("userSshCaId").withSchema(TableName.SshHost),
|
||||
db.ref("hostSshCaId").withSchema(TableName.SshHost)
|
||||
)
|
||||
@@ -163,10 +184,12 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.SshHostLoginUserMapping}.userId`, `${TableName.Users}.id`)
|
||||
.leftJoin(TableName.Groups, `${TableName.SshHostLoginUserMapping}.groupId`, `${TableName.Groups}.id`)
|
||||
.select(
|
||||
db.ref("sshHostId").withSchema(TableName.SshHostGroupMembership),
|
||||
db.ref("loginUser").withSchema(TableName.SshHostLoginUser),
|
||||
db.ref("username").withSchema(TableName.Users)
|
||||
db.ref("username").withSchema(TableName.Users),
|
||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
|
||||
)
|
||||
.whereIn(`${TableName.SshHostGroupMembership}.sshHostId`, hostIds);
|
||||
|
||||
@@ -185,7 +208,8 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
const directMappings = Object.entries(loginMappingGrouped).map(([loginUser, entries]) => ({
|
||||
loginUser,
|
||||
allowedPrincipals: {
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean)
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean),
|
||||
groups: unique(entries.map((e) => e.groupSlug)).filter(Boolean)
|
||||
},
|
||||
source: LoginMappingSource.HOST
|
||||
}));
|
||||
@@ -197,7 +221,8 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
const groupMappings = Object.entries(inheritedGrouped).map(([loginUser, entries]) => ({
|
||||
loginUser,
|
||||
allowedPrincipals: {
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean)
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean),
|
||||
groups: unique(entries.map((e) => e.groupSlug)).filter(Boolean)
|
||||
},
|
||||
source: LoginMappingSource.HOST_GROUP
|
||||
}));
|
||||
@@ -229,6 +254,7 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.SshHostLoginUserMapping}.userId`, `${TableName.Users}.id`)
|
||||
.leftJoin(TableName.Groups, `${TableName.SshHostLoginUserMapping}.groupId`, `${TableName.Groups}.id`)
|
||||
.where(`${TableName.SshHost}.id`, sshHostId)
|
||||
.select(
|
||||
db.ref("id").withSchema(TableName.SshHost).as("sshHostId"),
|
||||
@@ -241,7 +267,8 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
db.ref("username").withSchema(TableName.Users),
|
||||
db.ref("userId").withSchema(TableName.SshHostLoginUserMapping),
|
||||
db.ref("userSshCaId").withSchema(TableName.SshHost),
|
||||
db.ref("hostSshCaId").withSchema(TableName.SshHost)
|
||||
db.ref("hostSshCaId").withSchema(TableName.SshHost),
|
||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
|
||||
);
|
||||
|
||||
if (rows.length === 0) return null;
|
||||
@@ -257,7 +284,8 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
const directMappings = Object.entries(directGrouped).map(([loginUser, entries]) => ({
|
||||
loginUser,
|
||||
allowedPrincipals: {
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean)
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean),
|
||||
groups: unique(entries.map((e) => e.groupSlug)).filter(Boolean)
|
||||
},
|
||||
source: LoginMappingSource.HOST
|
||||
}));
|
||||
@@ -275,10 +303,12 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
`${TableName.SshHostLoginUserMapping}.sshHostLoginUserId`
|
||||
)
|
||||
.leftJoin(TableName.Users, `${TableName.SshHostLoginUserMapping}.userId`, `${TableName.Users}.id`)
|
||||
.leftJoin(TableName.Groups, `${TableName.SshHostLoginUserMapping}.groupId`, `${TableName.Groups}.id`)
|
||||
.where(`${TableName.SshHostGroupMembership}.sshHostId`, sshHostId)
|
||||
.select(
|
||||
db.ref("loginUser").withSchema(TableName.SshHostLoginUser),
|
||||
db.ref("username").withSchema(TableName.Users)
|
||||
db.ref("username").withSchema(TableName.Users),
|
||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
|
||||
);
|
||||
|
||||
const groupGrouped = groupBy(
|
||||
@@ -289,7 +319,8 @@ export const sshHostDALFactory = (db: TDbClient) => {
|
||||
const groupMappings = Object.entries(groupGrouped).map(([loginUser, entries]) => ({
|
||||
loginUser,
|
||||
allowedPrincipals: {
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean)
|
||||
usernames: unique(entries.map((e) => e.username)).filter(Boolean),
|
||||
groups: unique(entries.map((e) => e.groupSlug)).filter(Boolean)
|
||||
},
|
||||
source: LoginMappingSource.HOST_GROUP
|
||||
}));
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Knex } from "knex";
|
||||
import { ActionProjectType } from "@app/db/schemas";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
|
||||
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "../permission/project-permission";
|
||||
import { TCreateSshLoginMappingsDTO } from "./ssh-host-types";
|
||||
|
||||
/**
|
||||
@@ -15,6 +16,7 @@ export const createSshLoginMappings = async ({
|
||||
loginMappings,
|
||||
sshHostLoginUserDAL,
|
||||
sshHostLoginUserMappingDAL,
|
||||
groupDAL,
|
||||
userDAL,
|
||||
permissionService,
|
||||
projectId,
|
||||
@@ -35,7 +37,7 @@ export const createSshLoginMappings = async ({
|
||||
tx
|
||||
);
|
||||
|
||||
if (allowedPrincipals.usernames.length > 0) {
|
||||
if (allowedPrincipals.usernames && allowedPrincipals.usernames.length > 0) {
|
||||
const users = await userDAL.find(
|
||||
{
|
||||
$in: {
|
||||
@@ -74,6 +76,41 @@ export const createSshLoginMappings = async ({
|
||||
tx
|
||||
);
|
||||
}
|
||||
|
||||
if (allowedPrincipals.groups && allowedPrincipals.groups.length > 0) {
|
||||
const projectGroups = await groupDAL.findGroupsByProjectId(projectId);
|
||||
const groups = projectGroups.filter((g) => allowedPrincipals.groups?.includes(g.slug));
|
||||
|
||||
if (groups.length !== allowedPrincipals.groups?.length) {
|
||||
throw new BadRequestError({
|
||||
message: `Invalid group slugs: ${allowedPrincipals.groups
|
||||
.filter((g) => !projectGroups.some((pg) => pg.slug === g))
|
||||
.join(", ")}`
|
||||
});
|
||||
}
|
||||
|
||||
for await (const group of groups) {
|
||||
// check that each group has access to the SSH project and have read access to hosts
|
||||
const hasPermission = await permissionService.checkGroupProjectPermission({
|
||||
groupId: group.id,
|
||||
projectId,
|
||||
checkPermissions: [ProjectPermissionSshHostActions.Read, ProjectPermissionSub.SshHosts]
|
||||
});
|
||||
if (!hasPermission) {
|
||||
throw new BadRequestError({
|
||||
message: `Group ${group.slug} does not have access to the SSH project`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await sshHostLoginUserMappingDAL.insertMany(
|
||||
groups.map((group) => ({
|
||||
sshHostLoginUserId: sshHostLoginUser.id,
|
||||
groupId: group.id
|
||||
})),
|
||||
tx
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -14,10 +14,25 @@ export const sanitizedSshHost = SshHostsSchema.pick({
|
||||
});
|
||||
|
||||
export const loginMappingSchema = z.object({
|
||||
loginUser: z.string().trim().min(1).max(32),
|
||||
allowedPrincipals: z.object({
|
||||
usernames: z
|
||||
.array(z.string().trim())
|
||||
.transform((usernames) => Array.from(new Set(usernames.filter((username) => username !== ""))))
|
||||
})
|
||||
loginUser: z.string().trim(),
|
||||
allowedPrincipals: z
|
||||
.object({
|
||||
usernames: z
|
||||
.array(z.string().trim())
|
||||
.transform((usernames) => Array.from(new Set(usernames)))
|
||||
.optional(),
|
||||
groups: z
|
||||
.array(z.string().trim())
|
||||
.transform((groups) => Array.from(new Set(groups)))
|
||||
.optional()
|
||||
})
|
||||
.refine(
|
||||
(data) => {
|
||||
return (data.usernames && data.usernames.length > 0) || (data.groups && data.groups.length > 0);
|
||||
},
|
||||
{
|
||||
message: "At least one username or group must be provided",
|
||||
path: ["allowedPrincipals"]
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ForbiddenError, subject } from "@casl/ability";
|
||||
|
||||
import { ActionProjectType, ProjectType } from "@app/db/schemas";
|
||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
|
||||
import { ProjectPermissionSshHostActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
|
||||
import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal";
|
||||
@@ -19,6 +20,7 @@ import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||
import { TProjectSshConfigDALFactory } from "@app/services/project/project-ssh-config-dal";
|
||||
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||
|
||||
import { TUserGroupMembershipDALFactory } from "../group/user-group-membership-dal";
|
||||
import {
|
||||
convertActorToPrincipals,
|
||||
createSshCert,
|
||||
@@ -39,12 +41,14 @@ import {
|
||||
|
||||
type TSshHostServiceFactoryDep = {
|
||||
userDAL: Pick<TUserDALFactory, "findById" | "find">;
|
||||
groupDAL: Pick<TGroupDALFactory, "findGroupsByProjectId">;
|
||||
projectDAL: Pick<TProjectDALFactory, "find">;
|
||||
projectSshConfigDAL: Pick<TProjectSshConfigDALFactory, "findOne">;
|
||||
sshCertificateAuthorityDAL: Pick<TSshCertificateAuthorityDALFactory, "findOne">;
|
||||
sshCertificateAuthoritySecretDAL: Pick<TSshCertificateAuthoritySecretDALFactory, "findOne">;
|
||||
sshCertificateDAL: Pick<TSshCertificateDALFactory, "create" | "transaction">;
|
||||
sshCertificateBodyDAL: Pick<TSshCertificateBodyDALFactory, "create">;
|
||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "findGroupMembershipsByUserIdInOrg">;
|
||||
sshHostDAL: Pick<
|
||||
TSshHostDALFactory,
|
||||
| "transaction"
|
||||
@@ -58,7 +62,10 @@ type TSshHostServiceFactoryDep = {
|
||||
>;
|
||||
sshHostLoginUserDAL: TSshHostLoginUserDALFactory;
|
||||
sshHostLoginUserMappingDAL: TSshHostLoginUserMappingDALFactory;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getUserProjectPermission">;
|
||||
permissionService: Pick<
|
||||
TPermissionServiceFactory,
|
||||
"getProjectPermission" | "getUserProjectPermission" | "checkGroupProjectPermission"
|
||||
>;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
};
|
||||
|
||||
@@ -66,6 +73,8 @@ export type TSshHostServiceFactory = ReturnType<typeof sshHostServiceFactory>;
|
||||
|
||||
export const sshHostServiceFactory = ({
|
||||
userDAL,
|
||||
userGroupMembershipDAL,
|
||||
groupDAL,
|
||||
projectDAL,
|
||||
projectSshConfigDAL,
|
||||
sshCertificateAuthorityDAL,
|
||||
@@ -208,6 +217,7 @@ export const sshHostServiceFactory = ({
|
||||
loginMappings,
|
||||
sshHostLoginUserDAL,
|
||||
sshHostLoginUserMappingDAL,
|
||||
groupDAL,
|
||||
userDAL,
|
||||
permissionService,
|
||||
projectId,
|
||||
@@ -278,6 +288,7 @@ export const sshHostServiceFactory = ({
|
||||
loginMappings,
|
||||
sshHostLoginUserDAL,
|
||||
sshHostLoginUserMappingDAL,
|
||||
groupDAL,
|
||||
userDAL,
|
||||
permissionService,
|
||||
projectId: host.projectId,
|
||||
@@ -387,10 +398,14 @@ export const sshHostServiceFactory = ({
|
||||
userDAL
|
||||
});
|
||||
|
||||
const userGroups = await userGroupMembershipDAL.findGroupMembershipsByUserIdInOrg(actorId, actorOrgId);
|
||||
const userGroupSlugs = userGroups.map((g) => g.groupSlug);
|
||||
|
||||
const mapping = host.loginMappings.find(
|
||||
(m) =>
|
||||
m.loginUser === loginUser &&
|
||||
m.allowedPrincipals.usernames.some((allowed) => internalPrincipals.includes(allowed))
|
||||
(m.allowedPrincipals.usernames?.some((allowed) => internalPrincipals.includes(allowed)) ||
|
||||
m.allowedPrincipals.groups?.some((allowed) => userGroupSlugs.includes(allowed)))
|
||||
);
|
||||
|
||||
if (!mapping) {
|
||||
|
||||
@@ -7,12 +7,15 @@ import { TProjectPermission } from "@app/lib/types";
|
||||
import { ActorAuthMethod } from "@app/services/auth/auth-type";
|
||||
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||
|
||||
import { TGroupDALFactory } from "../group/group-dal";
|
||||
|
||||
export type TListSshHostsDTO = Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TLoginMapping = {
|
||||
loginUser: string;
|
||||
allowedPrincipals: {
|
||||
usernames: string[];
|
||||
usernames?: string[];
|
||||
groups?: string[];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -63,7 +66,8 @@ type BaseCreateSshLoginMappingsDTO = {
|
||||
sshHostLoginUserDAL: Pick<TSshHostLoginUserDALFactory, "create" | "transaction">;
|
||||
sshHostLoginUserMappingDAL: Pick<TSshHostLoginUserMappingDALFactory, "insertMany">;
|
||||
userDAL: Pick<TUserDALFactory, "find">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getUserProjectPermission">;
|
||||
permissionService: Pick<TPermissionServiceFactory, "getUserProjectPermission" | "checkGroupProjectPermission">;
|
||||
groupDAL: Pick<TGroupDALFactory, "findGroupsByProjectId">;
|
||||
projectId: string;
|
||||
actorAuthMethod: ActorAuthMethod;
|
||||
actorOrgId: string;
|
||||
|
||||
Reference in New Issue
Block a user