Bring back ssh host read permission

This commit is contained in:
Tuan Dang
2025-04-10 21:48:25 -07:00
parent 264177638f
commit edf375ca48
11 changed files with 82 additions and 31 deletions

View File

@@ -412,7 +412,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.sshHostId)
}),
response: {
200: z.string()
200: z.string().describe(SSH_HOSTS.GET_USER_CA_PUBLIC_KEY.publicKey)
}
},
handler: async (req) => {
@@ -433,7 +433,7 @@ export const registerSshHostRouter = async (server: FastifyZodProvider) => {
sshHostId: z.string().trim().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.sshHostId)
}),
response: {
200: z.string()
200: z.string().describe(SSH_HOSTS.GET_HOST_CA_PUBLIC_KEY.publicKey)
}
},
handler: async (req) => {

View File

@@ -68,6 +68,7 @@ export enum ProjectPermissionGroupActions {
}
export enum ProjectPermissionSshHostActions {
Read = "read",
Create = "create",
Edit = "edit",
Delete = "delete",
@@ -657,6 +658,7 @@ const buildAdminPermissionRules = () => {
can(
[
ProjectPermissionSshHostActions.Edit,
ProjectPermissionSshHostActions.Read,
ProjectPermissionSshHostActions.Create,
ProjectPermissionSshHostActions.Delete,
ProjectPermissionSshHostActions.IssueHostCert
@@ -924,6 +926,8 @@ const buildMemberPermissionRules = () => {
can([ProjectPermissionActions.Create], ProjectPermissionSub.SshCertificates);
can([ProjectPermissionActions.Read], ProjectPermissionSub.SshCertificateTemplates);
can([ProjectPermissionSshHostActions.Read], ProjectPermissionSub.SshHosts);
can(
[
ProjectPermissionCmekActions.Create,

View File

@@ -415,7 +415,7 @@ export const sshHostServiceFactory = ({
});
}
await permissionService.getProjectPermission({
const { permission } = await permissionService.getProjectPermission({
actor,
actorId,
projectId: host.projectId,
@@ -424,6 +424,13 @@ export const sshHostServiceFactory = ({
actionProjectType: ActionProjectType.SSH
});
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSshHostActions.Read,
subject(ProjectPermissionSub.SshHosts, {
hostname: host.hostname
})
);
return host;
};

View File

@@ -430,7 +430,8 @@ export const validateExternalSshCaKeyPair = async (publicKey: string, privateKey
if (publicKey.trim() !== derivedPublicKey.trim()) {
throw new BadRequestError({
message: "Failed to validate matching SSH key pair."
message:
"Failed to validate matching SSH key pair: The provided public key does not match the public key derived from the private key."
});
}

View File

@@ -1381,10 +1381,12 @@ export const SSH_HOSTS = {
signedKey: "The SSH certificate or signed SSH public key."
},
GET_USER_CA_PUBLIC_KEY: {
sshHostId: "The ID of the SSH host to get the user SSH CA public key for."
sshHostId: "The ID of the SSH host to get the user SSH CA public key for.",
publicKey: "The public key of the user SSH CA linked to the SSH host."
},
GET_HOST_CA_PUBLIC_KEY: {
sshHostId: "The ID of the SSH host to get the host SSH CA public key for."
sshHostId: "The ID of the SSH host to get the host SSH CA public key for.",
publicKey: "The public key of the host SSH CA linked to the SSH host."
}
};

View File

@@ -1,4 +1,4 @@
import { ForbiddenError } from "@casl/ability";
import { ForbiddenError, subject } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import {
@@ -15,6 +15,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
import {
ProjectPermissionActions,
ProjectPermissionSecretActions,
ProjectPermissionSshHostActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { TProjectTemplateServiceFactory } from "@app/ee/services/project-template/project-template-service";
@@ -1077,7 +1078,7 @@ export const projectServiceFactory = ({
actor,
projectId
}: TListProjectSshHostsDTO) => {
await permissionService.getProjectPermission({
const { permission } = await permissionService.getProjectPermission({
actor,
actorId,
projectId,
@@ -1086,8 +1087,27 @@ export const projectServiceFactory = ({
actionProjectType: ActionProjectType.SSH
});
const allowedHosts = [];
// (dangtony98): room to optimize
const hosts = await sshHostDAL.findSshHostsWithLoginMappings(projectId);
return hosts;
for (const host of hosts) {
try {
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionSshHostActions.Read,
subject(ProjectPermissionSub.SshHosts, {
hostname: host.hostname
})
);
allowedHosts.push(host);
} catch {
// intentionally ignore projects where user lacks access
}
}
return allowedHosts;
};
/**