forked from EduCraft/curriculum-project-hub
feat: add organization tenant model
This commit is contained in:
@@ -38,6 +38,7 @@ export interface AuthorizationDecision {
|
||||
readonly action: AuthorizationAction;
|
||||
readonly resource: AuthorizationResource;
|
||||
readonly actor: ActorInput;
|
||||
readonly organizationId: string;
|
||||
readonly actorUserId?: string | undefined;
|
||||
readonly principals: readonly PrincipalRef[];
|
||||
readonly requiredRole: PermissionRole;
|
||||
@@ -60,7 +61,8 @@ export class PrismaPermissionAuthorizer implements PermissionAuthorizer {
|
||||
if (req.action === "role.trigger" && (req.roleId === undefined || req.roleId === "")) {
|
||||
throw new Error("role.trigger authorization requires roleId");
|
||||
}
|
||||
const resolution = await this.resolver.resolveActor(req.actor);
|
||||
const organizationId = await this.organizationForResource(req.resource);
|
||||
const resolution = await this.resolver.resolveActor(req.actor, { organizationId });
|
||||
const threshold = await this.requiredRole(req);
|
||||
if (threshold === "DISABLED") {
|
||||
return this.decision(req, resolution, {
|
||||
@@ -206,17 +208,45 @@ export class PrismaPermissionAuthorizer implements PermissionAuthorizer {
|
||||
private decision(
|
||||
req: AuthorizationRequest,
|
||||
resolution: PrincipalResolution,
|
||||
result: Omit<AuthorizationDecision, "action" | "resource" | "actor" | "actorUserId" | "principals">,
|
||||
result: Omit<AuthorizationDecision, "action" | "resource" | "actor" | "organizationId" | "actorUserId" | "principals">,
|
||||
): AuthorizationDecision {
|
||||
return {
|
||||
action: req.action,
|
||||
resource: req.resource,
|
||||
actor: req.actor,
|
||||
organizationId: resolution.organizationId,
|
||||
...(resolution.userId !== undefined ? { actorUserId: resolution.userId } : {}),
|
||||
principals: resolution.principals,
|
||||
...result,
|
||||
};
|
||||
}
|
||||
|
||||
private async organizationForResource(resource: AuthorizationResource): Promise<string> {
|
||||
switch (resource.type) {
|
||||
case "PROJECT": {
|
||||
const project = await this.prisma.project.findUnique({
|
||||
where: { id: resource.id },
|
||||
select: { organizationId: true },
|
||||
});
|
||||
if (project === null) {
|
||||
throw new Error(`authorization resource missing: PROJECT ${resource.id}`);
|
||||
}
|
||||
return project.organizationId;
|
||||
}
|
||||
case "PROJECT_GROUP": {
|
||||
const binding = await this.prisma.projectGroupBinding.findUnique({
|
||||
where: { chatId: resource.id },
|
||||
select: { project: { select: { organizationId: true } } },
|
||||
});
|
||||
if (binding === null) {
|
||||
throw new Error(`authorization resource missing: PROJECT_GROUP ${resource.id}`);
|
||||
}
|
||||
return binding.project.organizationId;
|
||||
}
|
||||
case "ARTIFACT":
|
||||
throw new Error("authorization for ARTIFACT resources requires an organization resolver");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createPermissionAuthorizer(
|
||||
|
||||
Reference in New Issue
Block a user