mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-14 06:51:28 +02:00
@@ -1,6 +1,12 @@
|
|||||||
import { db } from "@server/db";
|
import { db } from "@server/db";
|
||||||
import { and, eq, inArray } from "drizzle-orm";
|
import { and, eq, inArray, isNull, or } from "drizzle-orm";
|
||||||
import { roleResources, userResources } from "@server/db";
|
import {
|
||||||
|
rolePolicies,
|
||||||
|
roleResources,
|
||||||
|
resources,
|
||||||
|
userPolicies,
|
||||||
|
userResources
|
||||||
|
} from "@server/db";
|
||||||
|
|
||||||
export async function canUserAccessResource({
|
export async function canUserAccessResource({
|
||||||
userId,
|
userId,
|
||||||
@@ -11,9 +17,14 @@ export async function canUserAccessResource({
|
|||||||
resourceId: number;
|
resourceId: number;
|
||||||
roleIds: number[];
|
roleIds: number[];
|
||||||
}): Promise<boolean> {
|
}): Promise<boolean> {
|
||||||
const roleResourceAccess =
|
const [
|
||||||
|
roleResourceAccess,
|
||||||
|
rolePolicyAccess,
|
||||||
|
userResourceAccess,
|
||||||
|
userPolicyAccess
|
||||||
|
] = await Promise.all([
|
||||||
roleIds.length > 0
|
roleIds.length > 0
|
||||||
? await db
|
? db
|
||||||
.select()
|
.select()
|
||||||
.from(roleResources)
|
.from(roleResources)
|
||||||
.where(
|
.where(
|
||||||
@@ -23,26 +34,87 @@ export async function canUserAccessResource({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
: [];
|
: [],
|
||||||
|
roleIds.length > 0
|
||||||
if (roleResourceAccess.length > 0) {
|
? db
|
||||||
return true;
|
.select({
|
||||||
}
|
roleId: rolePolicies.roleId,
|
||||||
|
resourcePolicyId: rolePolicies.resourcePolicyId
|
||||||
const userResourceAccess = await db
|
})
|
||||||
.select()
|
.from(rolePolicies)
|
||||||
.from(userResources)
|
.innerJoin(
|
||||||
.where(
|
resources,
|
||||||
and(
|
// Shared policy wins; only use default policy when no shared
|
||||||
eq(userResources.userId, userId),
|
// policy is assigned to the resource.
|
||||||
eq(userResources.resourceId, resourceId)
|
or(
|
||||||
|
eq(
|
||||||
|
resources.resourcePolicyId,
|
||||||
|
rolePolicies.resourcePolicyId
|
||||||
|
),
|
||||||
|
and(
|
||||||
|
isNull(resources.resourcePolicyId),
|
||||||
|
eq(
|
||||||
|
resources.defaultResourcePolicyId,
|
||||||
|
rolePolicies.resourcePolicyId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resources.resourceId, resourceId),
|
||||||
|
inArray(rolePolicies.roleId, roleIds)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
: [],
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(userResources)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(userResources.userId, userId),
|
||||||
|
eq(userResources.resourceId, resourceId)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
.limit(1),
|
||||||
.limit(1);
|
db
|
||||||
|
.select({
|
||||||
|
userId: userPolicies.userId,
|
||||||
|
resourcePolicyId: userPolicies.resourcePolicyId
|
||||||
|
})
|
||||||
|
.from(userPolicies)
|
||||||
|
.innerJoin(
|
||||||
|
resources,
|
||||||
|
// Shared policy wins; only use default policy when no shared
|
||||||
|
// policy is assigned to the resource.
|
||||||
|
or(
|
||||||
|
eq(
|
||||||
|
resources.resourcePolicyId,
|
||||||
|
userPolicies.resourcePolicyId
|
||||||
|
),
|
||||||
|
and(
|
||||||
|
isNull(resources.resourcePolicyId),
|
||||||
|
eq(
|
||||||
|
resources.defaultResourcePolicyId,
|
||||||
|
userPolicies.resourcePolicyId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
eq(resources.resourceId, resourceId),
|
||||||
|
eq(userPolicies.userId, userId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.limit(1)
|
||||||
|
]);
|
||||||
|
|
||||||
if (userResourceAccess.length > 0) {
|
return (
|
||||||
return true;
|
roleResourceAccess.length > 0 ||
|
||||||
}
|
rolePolicyAccess.length > 0 ||
|
||||||
|
userResourceAccess.length > 0 ||
|
||||||
return false;
|
userPolicyAccess.length > 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
logsDb,
|
logsDb,
|
||||||
newts,
|
newts,
|
||||||
roles,
|
roles,
|
||||||
|
rolePolicies,
|
||||||
roleResources,
|
roleResources,
|
||||||
roleSiteResources,
|
roleSiteResources,
|
||||||
resources,
|
resources,
|
||||||
@@ -40,7 +41,7 @@ import HttpCode from "@server/types/HttpCode";
|
|||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { and, eq, inArray, or } from "drizzle-orm";
|
import { and, eq, inArray, isNull, or } from "drizzle-orm";
|
||||||
import { canUserAccessResource } from "@server/auth/canUserAccessResource";
|
import { canUserAccessResource } from "@server/auth/canUserAccessResource";
|
||||||
import { canUserAccessSiteResource } from "@server/auth/canUserAccessSiteResource";
|
import { canUserAccessSiteResource } from "@server/auth/canUserAccessSiteResource";
|
||||||
import { signPublicKey, getOrgCAKeys } from "@server/lib/sshCA";
|
import { signPublicKey, getOrgCAKeys } from "@server/lib/sshCA";
|
||||||
@@ -435,50 +436,106 @@ export async function signSshKey(
|
|||||||
usernameToUse = userOrg.pamUsername;
|
usernameToUse = userOrg.pamUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
const roleRows =
|
type RoleSshMeta = {
|
||||||
type === "private"
|
roleId: number;
|
||||||
? await db
|
sshSudoCommands: string | null;
|
||||||
.select({
|
sshUnixGroups: string | null;
|
||||||
sshSudoCommands: roles.sshSudoCommands,
|
sshCreateHomeDir: boolean | null;
|
||||||
sshUnixGroups: roles.sshUnixGroups,
|
sshSudoMode: string | null;
|
||||||
sshCreateHomeDir: roles.sshCreateHomeDir,
|
};
|
||||||
sshSudoMode: roles.sshSudoMode
|
|
||||||
})
|
let roleRows: RoleSshMeta[] = [];
|
||||||
.from(roles)
|
|
||||||
.innerJoin(
|
if (type === "private") {
|
||||||
roleSiteResources,
|
roleRows = await db
|
||||||
eq(roleSiteResources.roleId, roles.roleId)
|
.select({
|
||||||
)
|
roleId: roles.roleId,
|
||||||
.where(
|
sshSudoCommands: roles.sshSudoCommands,
|
||||||
and(
|
sshUnixGroups: roles.sshUnixGroups,
|
||||||
inArray(roles.roleId, roleIds),
|
sshCreateHomeDir: roles.sshCreateHomeDir,
|
||||||
eq(
|
sshSudoMode: roles.sshSudoMode
|
||||||
roleSiteResources.siteResourceId,
|
})
|
||||||
(resource as SiteResource).siteResourceId
|
.from(roles)
|
||||||
)
|
.innerJoin(
|
||||||
)
|
roleSiteResources,
|
||||||
)
|
eq(roleSiteResources.roleId, roles.roleId)
|
||||||
: await db
|
)
|
||||||
.select({
|
.where(
|
||||||
sshSudoCommands: roles.sshSudoCommands,
|
and(
|
||||||
sshUnixGroups: roles.sshUnixGroups,
|
inArray(roles.roleId, roleIds),
|
||||||
sshCreateHomeDir: roles.sshCreateHomeDir,
|
eq(
|
||||||
sshSudoMode: roles.sshSudoMode
|
roleSiteResources.siteResourceId,
|
||||||
})
|
(resource as SiteResource).siteResourceId
|
||||||
.from(roles)
|
)
|
||||||
.innerJoin(
|
)
|
||||||
roleResources,
|
);
|
||||||
eq(roleResources.roleId, roles.roleId)
|
} else {
|
||||||
)
|
const publicResourceId = (resource as Resource).resourceId;
|
||||||
.where(
|
const [directRoleRows, policyRoleRows] = await Promise.all([
|
||||||
and(
|
db
|
||||||
inArray(roles.roleId, roleIds),
|
.select({
|
||||||
eq(
|
roleId: roles.roleId,
|
||||||
roleResources.resourceId,
|
sshSudoCommands: roles.sshSudoCommands,
|
||||||
(resource as Resource).resourceId
|
sshUnixGroups: roles.sshUnixGroups,
|
||||||
)
|
sshCreateHomeDir: roles.sshCreateHomeDir,
|
||||||
)
|
sshSudoMode: roles.sshSudoMode
|
||||||
);
|
})
|
||||||
|
.from(roles)
|
||||||
|
.innerJoin(
|
||||||
|
roleResources,
|
||||||
|
eq(roleResources.roleId, roles.roleId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(roles.roleId, roleIds),
|
||||||
|
eq(roleResources.resourceId, publicResourceId)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
db
|
||||||
|
.select({
|
||||||
|
roleId: roles.roleId,
|
||||||
|
sshSudoCommands: roles.sshSudoCommands,
|
||||||
|
sshUnixGroups: roles.sshUnixGroups,
|
||||||
|
sshCreateHomeDir: roles.sshCreateHomeDir,
|
||||||
|
sshSudoMode: roles.sshSudoMode
|
||||||
|
})
|
||||||
|
.from(roles)
|
||||||
|
.innerJoin(
|
||||||
|
rolePolicies,
|
||||||
|
eq(rolePolicies.roleId, roles.roleId)
|
||||||
|
)
|
||||||
|
.innerJoin(
|
||||||
|
resources,
|
||||||
|
or(
|
||||||
|
eq(
|
||||||
|
resources.resourcePolicyId,
|
||||||
|
rolePolicies.resourcePolicyId
|
||||||
|
),
|
||||||
|
and(
|
||||||
|
isNull(resources.resourcePolicyId),
|
||||||
|
eq(
|
||||||
|
resources.defaultResourcePolicyId,
|
||||||
|
rolePolicies.resourcePolicyId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
and(
|
||||||
|
inArray(roles.roleId, roleIds),
|
||||||
|
eq(resources.resourceId, publicResourceId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const uniqueByRoleId = new Map<number, RoleSshMeta>();
|
||||||
|
for (const row of [...directRoleRows, ...policyRoleRows]) {
|
||||||
|
if (!uniqueByRoleId.has(row.roleId)) {
|
||||||
|
uniqueByRoleId.set(row.roleId, row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roleRows = Array.from(uniqueByRoleId.values());
|
||||||
|
}
|
||||||
|
|
||||||
const parsedSudoCommands: string[] = [];
|
const parsedSudoCommands: string[] = [];
|
||||||
const parsedGroupsSet = new Set<string>();
|
const parsedGroupsSet = new Set<string>();
|
||||||
|
|||||||
Reference in New Issue
Block a user