feat(rbac): added new zod validation and permission check for all org level api

This commit is contained in:
Akhil Mohan
2023-09-08 21:20:29 +05:30
parent 96437fd1b7
commit e342e88499
27 changed files with 1870 additions and 1593 deletions
+32 -22
View File
@@ -2,6 +2,7 @@ import { AbilityBuilder, MongoAbility, RawRuleOf, createMongoAbility } from "@ca
import { MembershipOrg } from "../models";
import { IRole } from "../models/role";
import { BadRequestError, UnauthorizedRequestError } from "../utils/errors";
import { ACCEPTED } from "../variables";
export enum GeneralPermissionActions {
Read = "read",
@@ -10,34 +11,37 @@ export enum GeneralPermissionActions {
Delete = "delete"
}
export enum WorkspacePermissionActions {
Read = "read",
Create = "create"
}
export enum OrgPermissionSubjects {
Workspace = "workspace",
Role = "role",
Member = "member",
Settings = "settings",
ServiceAccount = "service-account",
IncidentAccount = "incident-contact",
Sso = "sso",
Billing = "billing"
Billing = "billing",
SecretScanning = "secret-scanning"
}
export type OrgPermissionSet =
| [GeneralPermissionActions, OrgPermissionSubjects.Workspace]
| [WorkspacePermissionActions, OrgPermissionSubjects.Workspace]
| [GeneralPermissionActions, OrgPermissionSubjects.Role]
| [GeneralPermissionActions, OrgPermissionSubjects.Member]
| [GeneralPermissionActions, OrgPermissionSubjects.Settings]
| [GeneralPermissionActions, OrgPermissionSubjects.ServiceAccount]
| [GeneralPermissionActions, OrgPermissionSubjects.IncidentAccount]
| [GeneralPermissionActions, OrgPermissionSubjects.Sso]
| [GeneralPermissionActions, OrgPermissionSubjects.SecretScanning]
| [GeneralPermissionActions, OrgPermissionSubjects.Billing];
const buildAdminPermission = () => {
const { can, build } = new AbilityBuilder<MongoAbility<OrgPermissionSet>>(createMongoAbility);
// ws permissions
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Workspace);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.Workspace);
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.Workspace);
can(GeneralPermissionActions.Delete, OrgPermissionSubjects.Workspace);
can(WorkspacePermissionActions.Read, OrgPermissionSubjects.Workspace);
can(WorkspacePermissionActions.Create, OrgPermissionSubjects.Workspace);
// role permission
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Role);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.Role);
@@ -49,16 +53,16 @@ const buildAdminPermission = () => {
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.Member);
can(GeneralPermissionActions.Delete, OrgPermissionSubjects.Member);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
can(GeneralPermissionActions.Delete, OrgPermissionSubjects.SecretScanning);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Settings);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.Settings);
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.Settings);
can(GeneralPermissionActions.Delete, OrgPermissionSubjects.Settings);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.ServiceAccount);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.ServiceAccount);
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.ServiceAccount);
can(GeneralPermissionActions.Delete, OrgPermissionSubjects.ServiceAccount);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.IncidentAccount);
can(GeneralPermissionActions.Create, OrgPermissionSubjects.IncidentAccount);
can(GeneralPermissionActions.Edit, OrgPermissionSubjects.IncidentAccount);
@@ -82,14 +86,15 @@ export const adminPermissions = buildAdminPermission();
const buildMemberPermission = () => {
const { can, build } = new AbilityBuilder<MongoAbility<OrgPermissionSet>>(createMongoAbility);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Workspace);
can(WorkspacePermissionActions.Read, OrgPermissionSubjects.Workspace);
can(WorkspacePermissionActions.Create, OrgPermissionSubjects.Workspace);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Member);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Role);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Settings);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Billing);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.Sso);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.IncidentAccount);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.ServiceAccount);
can(GeneralPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
return build();
};
@@ -98,23 +103,28 @@ export const memberPermissions = buildMemberPermission();
export const getUserOrgPermissions = async (userId: string, orgId: string) => {
// TODO(akhilmhdh): speed this up by pulling from cache later
const orgMembership = await MembershipOrg.findOne({ user: userId, organization: orgId })
const membership = await MembershipOrg.findOne({
user: userId,
organization: orgId,
status: ACCEPTED
})
.populate<{ customRole: IRole & { permissions: RawRuleOf<MongoAbility<OrgPermissionSet>>[] } }>(
"customRole"
)
.exec();
if (!orgMembership || (orgMembership.role === "custom" && !orgMembership.customRole)) {
if (!membership || (membership.role === "custom" && !membership.customRole)) {
throw UnauthorizedRequestError({ message: "User doesn't belong to organization" });
}
if (orgMembership.role === "admin" || orgMembership.role === "owner") return adminPermissions;
if (membership.role === "admin" || membership.role === "owner")
return { permission: adminPermissions, membership };
if (orgMembership.role === "member") return memberPermissions;
if (membership.role === "member") return { permission: memberPermissions, membership };
if (orgMembership.role === "custom") {
const permission = createMongoAbility<OrgPermissionSet>(orgMembership.customRole.permissions);
return permission;
if (membership.role === "custom") {
const permission = createMongoAbility<OrgPermissionSet>(membership.customRole.permissions);
return { permission, membership };
}
throw BadRequestError({ message: "User role not found" });