Replace most getUserOrgPermissions with more generic getAuthDataOrgPermissions for MIs in backend

This commit is contained in:
Tuan Dang
2023-12-05 19:20:30 +07:00
parent 3c449214d1
commit 87e997e7a0
13 changed files with 326 additions and 76 deletions
@@ -21,7 +21,7 @@ import { validateRequest } from "../../helpers/validation";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -45,10 +45,11 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
throw new Error("Failed to delete organization membership that doesn't exist"); throw new Error("Failed to delete organization membership that doesn't exist");
} }
const { permission, membership: membershipOrg } = await getUserOrgPermissions( const { permission } = await getAuthDataOrgPermissions({
req.user._id, authData: req.authData,
membershipOrgToDelete.organization.toString() organizationId: membershipOrgToDelete.organization
); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -60,7 +61,7 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
}); });
await updateSubscriptionOrgQuantity({ await updateSubscriptionOrgQuantity({
organizationId: membershipOrg.organization.toString() organizationId: membershipOrgToDelete.organization.toString()
}); });
return membershipOrgToDelete; return membershipOrgToDelete;
@@ -96,7 +97,11 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
body: { inviteeEmail, organizationId } body: { inviteeEmail, organizationId }
} = await validateRequest(reqValidator.InviteUserToOrgv1, req); } = await validateRequest(reqValidator.InviteUserToOrgv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -1,4 +1,5 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import { Types } from "mongoose";
import { import {
IncidentContactOrg, IncidentContactOrg,
Membership, Membership,
@@ -14,7 +15,7 @@ import { ACCEPTED } from "../../variables";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { OrganizationNotFoundError } from "../../utils/errors"; import { OrganizationNotFoundError } from "../../utils/errors";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -44,7 +45,10 @@ export const getOrganization = async (req: Request, res: Response) => {
} = await validateRequest(reqValidator.GetOrgv1, req); } = await validateRequest(reqValidator.GetOrgv1, req);
// ensure user has membership // ensure user has membership
await getUserOrgPermissions(req.user._id, organizationId); await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
})
const organization = await Organization.findById(organizationId); const organization = await Organization.findById(organizationId);
if (!organization) { if (!organization) {
@@ -69,7 +73,11 @@ export const getOrganizationMembers = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgMembersv1, req); } = await validateRequest(reqValidator.GetOrgMembersv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -95,7 +103,10 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgWorkspacesv1, req); } = await validateRequest(reqValidator.GetOrgWorkspacesv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
})
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Workspace OrgPermissionSubjects.Workspace
@@ -137,7 +148,10 @@ export const changeOrganizationName = async (req: Request, res: Response) => {
body: { name } body: { name }
} = await validateRequest(reqValidator.ChangeOrgNamev1, req); } = await validateRequest(reqValidator.ChangeOrgNamev1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.Settings OrgPermissionSubjects.Settings
@@ -172,7 +186,10 @@ export const getOrganizationIncidentContacts = async (req: Request, res: Respons
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgIncidentContactv1, req); } = await validateRequest(reqValidator.GetOrgIncidentContactv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.IncidentAccount OrgPermissionSubjects.IncidentAccount
@@ -199,7 +216,10 @@ export const addOrganizationIncidentContact = async (req: Request, res: Response
body: { email } body: { email }
} = await validateRequest(reqValidator.CreateOrgIncideContact, req); } = await validateRequest(reqValidator.CreateOrgIncideContact, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.IncidentAccount OrgPermissionSubjects.IncidentAccount
@@ -228,7 +248,10 @@ export const deleteOrganizationIncidentContact = async (req: Request, res: Respo
body: { email } body: { email }
} = await validateRequest(reqValidator.DelOrgIncideContact, req); } = await validateRequest(reqValidator.DelOrgIncideContact, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.IncidentAccount OrgPermissionSubjects.IncidentAccount
@@ -257,7 +280,10 @@ export const createOrganizationPortalSession = async (req: Request, res: Respons
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req); } = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -321,7 +347,10 @@ export const getOrganizationMembersAndTheirWorkspaces = async (req: Request, res
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgMembersv1, req); } = await validateRequest(reqValidator.GetOrgMembersv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -21,7 +21,7 @@ import * as reqValidator from "../../validation/secretScanning";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -38,7 +38,10 @@ export const createInstallationSession = async (req: Request, res: Response) =>
}); });
} }
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.SecretScanning OrgPermissionSubjects.SecretScanning
@@ -71,10 +74,11 @@ export const linkInstallationToOrganization = async (req: Request, res: Response
throw UnauthorizedRequestError(); throw UnauthorizedRequestError();
} }
const { permission } = await getUserOrgPermissions( const { permission } = await getAuthDataOrgPermissions({
req.user._id, authData: req.authData,
installationSession.organization.toString() organizationId: installationSession.organization
); });
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.SecretScanning OrgPermissionSubjects.SecretScanning
@@ -142,7 +146,10 @@ export const getRisksForOrganization = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgRisksv1, req); } = await validateRequest(reqValidator.GetOrgRisksv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.SecretScanning OrgPermissionSubjects.SecretScanning
@@ -162,7 +169,10 @@ export const updateRisksStatus = async (req: Request, res: Response) => {
body: { status } body: { status }
} = await validateRequest(reqValidator.UpdateRiskStatusv1, req); } = await validateRequest(reqValidator.UpdateRiskStatusv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.SecretScanning OrgPermissionSubjects.SecretScanning
@@ -17,7 +17,7 @@ import { OrganizationNotFoundError } from "../../utils/errors";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { validateRequest } from "../../helpers/validation"; import { validateRequest } from "../../helpers/validation";
@@ -152,7 +152,10 @@ export const createWorkspace = async (req: Request, res: Response) => {
}); });
} }
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Workspace OrgPermissionSubjects.Workspace
@@ -14,14 +14,14 @@ import {
updateSubscriptionOrgQuantity updateSubscriptionOrgQuantity
} from "../../helpers/organization"; } from "../../helpers/organization";
import { addMembershipsOrg } from "../../helpers/membershipOrg"; import { addMembershipsOrg } from "../../helpers/membershipOrg";
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, ResourceNotFoundError, UnauthorizedRequestError } from "../../utils/errors";
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS } from "../../variables"; import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS } from "../../variables";
import * as reqValidator from "../../validation/organization"; import * as reqValidator from "../../validation/organization";
import { validateRequest } from "../../helpers/validation"; import { validateRequest } from "../../helpers/validation";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../ee/services/RoleService"; } from "../../ee/services/RoleService";
import { EELicenseService } from "../../ee/services"; import { EELicenseService } from "../../ee/services";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -69,7 +69,10 @@ export const getOrganizationMemberships = async (req: Request, res: Response) =>
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgMembersv2, req); } = await validateRequest(reqValidator.GetOrgMembersv2, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -147,7 +150,11 @@ export const updateOrganizationMembership = async (req: Request, res: Response)
params: { organizationId, membershipId }, params: { organizationId, membershipId },
body: { role } body: { role }
} = await validateRequest(reqValidator.UpdateOrgMemberv2, req); } = await validateRequest(reqValidator.UpdateOrgMemberv2, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -245,7 +252,18 @@ export const deleteOrganizationMembership = async (req: Request, res: Response)
const { const {
params: { organizationId, membershipId } params: { organizationId, membershipId }
} = await validateRequest(reqValidator.DeleteOrgMemberv2, req); } = await validateRequest(reqValidator.DeleteOrgMemberv2, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const membershipOrg = await MembershipOrg.findOne({
_id: new Types.ObjectId(membershipId),
organization: new Types.ObjectId(organizationId)
});
if (!membershipOrg) throw ResourceNotFoundError();
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: membershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.Member OrgPermissionSubjects.Member
@@ -309,7 +327,11 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgWorkspacesv2, req); } = await validateRequest(reqValidator.GetOrgWorkspacesv2, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Workspace OrgPermissionSubjects.Workspace
@@ -407,8 +429,10 @@ export const getOrganizationMachineMemberships = async (req: Request, res: Respo
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgServiceMembersV2, req); } = await validateRequest(reqValidator.GetOrgServiceMembersV2, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.MachineIdentity OrgPermissionSubjects.MachineIdentity
@@ -8,7 +8,7 @@ import * as reqValidator from "../../../validation/organization";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions,
} from "../../services/RoleService"; } from "../../services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
import { Organization } from "../../../models"; import { Organization } from "../../../models";
@@ -20,7 +20,10 @@ export const getOrganizationPlansTable = async (req: Request, res: Response) =>
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlansTablev1, req); } = await validateRequest(reqValidator.GetOrgPlansTablev1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -42,7 +45,10 @@ export const getOrganizationPlan = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlanv1, req); } = await validateRequest(reqValidator.GetOrgPlanv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -70,7 +76,10 @@ export const startOrganizationTrial = async (req: Request, res: Response) => {
body: { success_url } body: { success_url }
} = await validateRequest(reqValidator.StartOrgTrailv1, req); } = await validateRequest(reqValidator.StartOrgTrailv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -116,7 +125,10 @@ export const getOrganizationPlanBillingInfo = async (req: Request, res: Response
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req); } = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -149,7 +161,10 @@ export const getOrganizationPlanTable = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlanTablev1, req); } = await validateRequest(reqValidator.GetOrgPlanTablev1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -176,7 +191,10 @@ export const getOrganizationBillingDetails = async (req: Request, res: Response)
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgBillingDetailsv1, req); } = await validateRequest(reqValidator.GetOrgBillingDetailsv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -204,7 +222,10 @@ export const updateOrganizationBillingDetails = async (req: Request, res: Respon
body: { name, email } body: { name, email }
} = await validateRequest(reqValidator.UpdateOrgBillingDetailsv1, req); } = await validateRequest(reqValidator.UpdateOrgBillingDetailsv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -238,7 +259,10 @@ export const getOrganizationPmtMethods = async (req: Request, res: Response) =>
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPmtMethodsv1, req); } = await validateRequest(reqValidator.GetOrgPmtMethodsv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -271,7 +295,10 @@ export const addOrganizationPmtMethod = async (req: Request, res: Response) => {
body: { success_url, cancel_url } body: { success_url, cancel_url }
} = await validateRequest(reqValidator.CreateOrgPmtMethodv1, req); } = await validateRequest(reqValidator.CreateOrgPmtMethodv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -312,7 +339,10 @@ export const deleteOrganizationPmtMethod = async (req: Request, res: Response) =
params: { organizationId, pmtMethodId } params: { organizationId, pmtMethodId }
} = await validateRequest(reqValidator.DelOrgPmtMethodv1, req); } = await validateRequest(reqValidator.DelOrgPmtMethodv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -342,7 +372,10 @@ export const getOrganizationTaxIds = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgTaxIdsv1, req); } = await validateRequest(reqValidator.GetOrgTaxIdsv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -375,7 +408,10 @@ export const addOrganizationTaxId = async (req: Request, res: Response) => {
body: { type, value } body: { type, value }
} = await validateRequest(reqValidator.CreateOrgTaxId, req); } = await validateRequest(reqValidator.CreateOrgTaxId, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -412,7 +448,10 @@ export const deleteOrganizationTaxId = async (req: Request, res: Response) => {
params: { organizationId, taxId } params: { organizationId, taxId }
} = await validateRequest(reqValidator.DelOrgTaxIdv1, req); } = await validateRequest(reqValidator.DelOrgTaxIdv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -445,7 +484,10 @@ export const getOrganizationInvoices = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgInvoicesv1, req); } = await validateRequest(reqValidator.GetOrgInvoicesv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -480,7 +522,10 @@ export const getOrganizationLicenses = async (req: Request, res: Response) => {
params: { organizationId } params: { organizationId }
} = await validateRequest(reqValidator.GetOrgLicencesv1, req); } = await validateRequest(reqValidator.GetOrgLicencesv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Billing OrgPermissionSubjects.Billing
@@ -22,6 +22,7 @@ import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
adminPermissions, adminPermissions,
getAuthDataOrgPermissions,
getUserOrgPermissions, getUserOrgPermissions,
memberPermissions, memberPermissions,
noAccessPermissions noAccessPermissions
@@ -38,7 +39,11 @@ export const createRole = async (req: Request, res: Response) => {
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
if (isOrgRole) { if (isOrgRole) {
const { permission } = await getUserOrgPermissions(req.user.id, orgId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(orgId)
});
if (permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Role)) { if (permission.cannot(OrgPermissionActions.Create, OrgPermissionSubjects.Role)) {
throw BadRequestError({ message: "user doesn't have the permission." }); throw BadRequestError({ message: "user doesn't have the permission." });
} }
@@ -84,7 +89,10 @@ export const updateRole = async (req: Request, res: Response) => {
const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule const isOrgRole = !workspaceId; // if workspaceid is provided then its a workspace rule
if (isOrgRole) { if (isOrgRole) {
const { permission } = await getUserOrgPermissions(req.user.id, orgId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(orgId)
});
if (permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.Role)) { if (permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.Role)) {
throw BadRequestError({ message: "User doesn't have the org permission." }); throw BadRequestError({ message: "User doesn't have the org permission." });
} }
@@ -140,7 +148,10 @@ export const deleteRole = async (req: Request, res: Response) => {
const isOrgRole = !role.workspace; const isOrgRole = !role.workspace;
if (isOrgRole) { if (isOrgRole) {
const { permission } = await getUserOrgPermissions(req.user.id, role.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: role.organization
});
if (permission.cannot(OrgPermissionActions.Delete, OrgPermissionSubjects.Role)) { if (permission.cannot(OrgPermissionActions.Delete, OrgPermissionSubjects.Role)) {
throw BadRequestError({ message: "User doesn't have the org permission." }); throw BadRequestError({ message: "User doesn't have the org permission." });
} }
@@ -172,7 +183,10 @@ export const getRoles = async (req: Request, res: Response) => {
const isOrgRole = !workspaceId; const isOrgRole = !workspaceId;
if (isOrgRole) { if (isOrgRole) {
const { permission } = await getUserOrgPermissions(req.user.id, orgId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(orgId)
});
if (permission.cannot(OrgPermissionActions.Read, OrgPermissionSubjects.Role)) { if (permission.cannot(OrgPermissionActions.Read, OrgPermissionSubjects.Role)) {
throw BadRequestError({ message: "User doesn't have the org permission." }); throw BadRequestError({ message: "User doesn't have the org permission." });
} }
+13 -4
View File
@@ -13,7 +13,7 @@ import { validateRequest } from "../../../helpers/validation";
import { import {
OrgPermissionActions, OrgPermissionActions,
OrgPermissionSubjects, OrgPermissionSubjects,
getUserOrgPermissions getAuthDataOrgPermissions
} from "../../services/RoleService"; } from "../../services/RoleService";
import { ForbiddenError } from "@casl/ability"; import { ForbiddenError } from "@casl/ability";
@@ -47,7 +47,10 @@ export const getSSOConfig = async (req: Request, res: Response) => {
query: { organizationId } query: { organizationId }
} = await validateRequest(reqValidator.GetSsoConfigv1, req); } = await validateRequest(reqValidator.GetSsoConfigv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.Sso OrgPermissionSubjects.Sso
@@ -71,7 +74,10 @@ export const updateSSOConfig = async (req: Request, res: Response) => {
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert } body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
} = await validateRequest(reqValidator.UpdateSsoConfigv1, req); } = await validateRequest(reqValidator.UpdateSsoConfigv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.Sso OrgPermissionSubjects.Sso
@@ -206,7 +212,10 @@ export const createSSOConfig = async (req: Request, res: Response) => {
body: { organizationId, authProvider, isActive, entryPoint, issuer, cert } body: { organizationId, authProvider, isActive, entryPoint, issuer, cert }
} = await validateRequest(reqValidator.CreateSsoConfigv1, req); } = await validateRequest(reqValidator.CreateSsoConfigv1, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
OrgPermissionSubjects.Sso OrgPermissionSubjects.Sso
@@ -22,8 +22,8 @@ import { validateRequest } from "../../../helpers/validation";
import * as reqValidator from "../../../validation/machineIdentity"; import * as reqValidator from "../../../validation/machineIdentity";
import { createToken } from "../../../helpers/auth"; import { createToken } from "../../../helpers/auth";
import { import {
getAuthDataOrgPermissions,
getOrgRolePermissions, getOrgRolePermissions,
getUserOrgPermissions,
isAtLeastAsPrivilegedOrg isAtLeastAsPrivilegedOrg
} from "../../services/RoleService"; } from "../../services/RoleService";
import { import {
@@ -76,8 +76,10 @@ export const getMIClientSecrets = async (req: Request, res: Response) => {
if (!machineMembershipOrg) throw ResourceNotFoundError(); if (!machineMembershipOrg) throw ResourceNotFoundError();
const { permission } = await getUserOrgPermissions(req.user._id, machineMembershipOrg.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: machineMembershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read, OrgPermissionActions.Read,
OrgPermissionSubjects.MachineIdentity OrgPermissionSubjects.MachineIdentity
@@ -146,7 +148,10 @@ export const createMIClientSecret = async (req: Request, res: Response) => {
if (!machineMembershipOrg) throw ResourceNotFoundError(); if (!machineMembershipOrg) throw ResourceNotFoundError();
const { permission } = await getUserOrgPermissions(req.user._id, machineMembershipOrg.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: machineMembershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
@@ -225,7 +230,10 @@ export const deleteMIClientSecret = async (req: Request, res: Response) => {
message: `Failed to find machine identity with id ${machineId}` message: `Failed to find machine identity with id ${machineId}`
}); });
const { permission } = await getUserOrgPermissions(req.user._id, machineMembershipOrg.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: machineMembershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
@@ -434,7 +442,10 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
} }
} = await validateRequest(reqValidator.CreateMachineIdentityV3, req); } = await validateRequest(reqValidator.CreateMachineIdentityV3, req);
const { permission } = await getUserOrgPermissions(req.user._id, organizationId); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create, OrgPermissionActions.Create,
@@ -567,7 +578,10 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
message: `Failed to find machine identity with id ${machineId}` message: `Failed to find machine identity with id ${machineId}`
}); });
const { permission } = await getUserOrgPermissions(req.user._id, machineMembershipOrg.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: machineMembershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit, OrgPermissionActions.Edit,
OrgPermissionSubjects.MachineIdentity OrgPermissionSubjects.MachineIdentity
@@ -725,7 +739,10 @@ export const deleteMachineIdentity = async (req: Request, res: Response) => {
message: `Failed to find machine identity with id ${machineId}` message: `Failed to find machine identity with id ${machineId}`
}); });
const { permission } = await getUserOrgPermissions(req.user._id, machineMembershipOrg.organization.toString()); const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: machineMembershipOrg.organization
});
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete, OrgPermissionActions.Delete,
OrgPermissionSubjects.MachineIdentity OrgPermissionSubjects.MachineIdentity
+1 -1
View File
@@ -1,4 +1,4 @@
export enum ActorType { export enum ActorType { // would extend to AWS, Azure, ...
USER = "user", USER = "user",
SERVICE = "service", SERVICE = "service",
MACHINE = "machine" MACHINE = "machine"
+96 -2
View File
@@ -1,10 +1,16 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { AbilityBuilder, MongoAbility, RawRuleOf, createMongoAbility } from "@casl/ability"; import { AbilityBuilder, MongoAbility, RawRuleOf, createMongoAbility } from "@casl/ability";
import { MembershipOrg } from "../../models"; import {
import { IRole, Role } from "../models"; IMachineIdentity,
MachineMembershipOrg,
MembershipOrg
} from "../../models";
import { ActorType, IRole, Role } from "../models";
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import { checkIPAgainstBlocklist } from "../../utils/ip";
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS} from "../../variables"; import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS} from "../../variables";
import { conditionsMatcher } from "./ProjectRoleService"; import { conditionsMatcher } from "./ProjectRoleService";
import { AuthData } from "../../interfaces/middleware";
export enum OrgPermissionActions { export enum OrgPermissionActions {
Read = "read", Read = "read",
@@ -156,6 +162,94 @@ export const getUserOrgPermissions = async (userId: string, orgId: string) => {
throw BadRequestError({ message: "User role not found" }); throw BadRequestError({ message: "User role not found" });
}; };
/**
* Return permissions for user/service pertaining to organization with id [organizationId]
*
* Note: should not rely on this function for ST V2 authorization logic
* b/c ST V2 does not support role-based access control but also not organization-level resources
*/
export const getAuthDataOrgPermissions = async ({
authData,
organizationId
}: {
authData: AuthData;
organizationId: Types.ObjectId;
}) => {
let role: "admin" | "member" | "no-access" | "custom";
let customRole;
switch (authData.actor.type) {
case ActorType.USER: {
const membershipOrg = await MembershipOrg.findOne({
user: authData.authPayload._id,
organization: organizationId,
status: ACCEPTED
})
.populate<{ customRole: IRole & { permissions: RawRuleOf<MongoAbility<OrgPermissionSet>>[] } }>(
"customRole"
)
.exec();
if (!membershipOrg || (membershipOrg.role === "custom" && !membershipOrg.customRole)) {
throw UnauthorizedRequestError({ message: "User doesn't belong to organization" });
}
role = membershipOrg.role;
customRole = membershipOrg.customRole;
break;
}
case ActorType.SERVICE: {
throw UnauthorizedRequestError({
message: "Failed to access organization-level resources with service token"
});
}
case ActorType.MACHINE: {
const machineMembershipOrg = await MachineMembershipOrg.findOne({
machineIdentity: authData.authPayload._id,
organization: organizationId
})
.populate<{
customRole: IRole & { permissions: RawRuleOf<MongoAbility<OrgPermissionSet>>[] };
machineIdentity: IMachineIdentity
}>("customRole machineIdentity")
.exec();
if (!machineMembershipOrg || (machineMembershipOrg.role === "custom" && !machineMembershipOrg.customRole)) {
throw UnauthorizedRequestError();
}
checkIPAgainstBlocklist({
ipAddress: authData.ipAddress,
trustedIps: machineMembershipOrg.machineIdentity.accessTokenTrustedIps
});
role = machineMembershipOrg.role;
customRole = machineMembershipOrg.customRole;
break;
}
default:
throw UnauthorizedRequestError();
}
switch (role) {
case ADMIN:
return { permission: adminPermissions };
case MEMBER:
return { permission: memberPermissions };
case NO_ACCESS:
return { permission: noAccessPermissions };
case CUSTOM: {
if (!customRole) throw UnauthorizedRequestError();
return {
permission: createMongoAbility<OrgPermissionSet>(
customRole.permissions,
{ conditionsMatcher }
)
};
}
}
}
export const getOrgRolePermissions = async (role: string, orgId: string) => { export const getOrgRolePermissions = async (role: string, orgId: string) => {
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role); const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
if (isCustomRole) { if (isCustomRole) {
+1 -1
View File
@@ -5,7 +5,7 @@ export interface IMachineMembershipOrg {
_id: Types.ObjectId; _id: Types.ObjectId;
machineIdentity: Types.ObjectId; machineIdentity: Types.ObjectId;
organization: Types.ObjectId; organization: Types.ObjectId;
role: "admin" | "member" | "viewer" | "no-access" | "custom"; role: "admin" | "member" | "no-access" | "custom";
customRole: Types.ObjectId; customRole: Types.ObjectId;
} }
+1 -1
View File
@@ -6,7 +6,7 @@ export interface IMembershipOrg extends Document {
user: Types.ObjectId; user: Types.ObjectId;
inviteEmail: string; inviteEmail: string;
organization: Types.ObjectId; organization: Types.ObjectId;
role: "owner" | "admin" | "member" | "no-access" | "custom"; role: "admin" | "member" | "no-access" | "custom";
customRole: Types.ObjectId; customRole: Types.ObjectId;
status: "invited" | "accepted"; status: "invited" | "accepted";
} }