Update orgScope to orgId naming for org-level auth ref, rewire user invite saml block to org authEnforce field

This commit is contained in:
Tuan Dang
2024-02-08 17:29:21 -08:00
parent 22d89d791c
commit 4e2f2281f9
69 changed files with 572 additions and 1183 deletions
+21 -10
View File
@@ -22,8 +22,13 @@ type TOrgRoleServiceFactoryDep = {
export type TOrgRoleServiceFactory = ReturnType<typeof orgRoleServiceFactory>;
export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRoleServiceFactoryDep) => {
const createRole = async (userId: string, orgId: string, data: Omit<TOrgRolesInsert, "orgId">, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const createRole = async (
userId: string,
orgId: string,
data: Omit<TOrgRolesInsert, "orgId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Role);
const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId });
if (existingRole) throw new BadRequestError({ name: "Create Role", message: "Duplicate role" });
@@ -35,8 +40,14 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return role;
};
const updateRole = async (userId: string, orgId: string, roleId: string, data: Omit<TOrgRolesUpdate, "orgId">, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const updateRole = async (
userId: string,
orgId: string,
roleId: string,
data: Omit<TOrgRolesUpdate, "orgId">,
actorOrgId?: string
) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Role);
if (data?.slug) {
const existingRole = await orgRoleDAL.findOne({ slug: data.slug, orgId });
@@ -51,8 +62,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return updatedRole;
};
const deleteRole = async (userId: string, orgId: string, roleId: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const deleteRole = async (userId: string, orgId: string, roleId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Role);
const [deletedRole] = await orgRoleDAL.delete({ id: roleId, orgId });
if (!deleteRole) throw new BadRequestError({ message: "Role not found", name: "Update role" });
@@ -60,8 +71,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return deletedRole;
};
const listRoles = async (userId: string, orgId: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const listRoles = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
const customRoles = await orgRoleDAL.find({ orgId });
const roles = [
@@ -104,8 +115,8 @@ export const orgRoleServiceFactory = ({ orgRoleDAL, permissionService }: TOrgRol
return roles;
};
const getUserPermission = async (userId: string, orgId: string, actorOrgScope?: string) => {
const { permission, membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const getUserPermission = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission, membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
return { permissions: packRules(permission.rules), membership };
};
+27 -26
View File
@@ -69,8 +69,8 @@ export const orgServiceFactory = ({
/*
* Get organization details by the organization id
* */
const findOrganizationById = async (userId: string, orgId: string, actorOrgScope?: string) => {
await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const findOrganizationById = async (userId: string, orgId: string, actorOrgId?: string) => {
await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
const org = await orgDAL.findOrgById(orgId);
if (!org) throw new BadRequestError({ name: "Org not found", message: "Organization not found" });
return org;
@@ -85,16 +85,16 @@ export const orgServiceFactory = ({
/*
* Get all workspace members
* */
const findAllOrgMembers = async (userId: string, orgId: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const findAllOrgMembers = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
const members = await orgDAL.findAllOrgMembers(orgId);
return members;
};
const findAllWorkspaces = async ({ actor, actorId, actorOrgScope, orgId }: TFindAllWorkspacesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
const findAllWorkspaces = async ({ actor, actorId, actorOrgId, orgId }: TFindAllWorkspacesDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Workspace);
const organizationWorkspaceIds = new Set((await projectDAL.find({ orgId })).map((workspace) => workspace.id));
@@ -124,11 +124,11 @@ export const orgServiceFactory = ({
const updateOrg = async ({
actor,
actorId,
actorOrgScope,
actorOrgId,
orgId,
data: { name, slug, authEnforced }
}: TUpdateOrgDTO) => {
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgScope);
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
if (authEnforced) {
@@ -212,8 +212,8 @@ export const orgServiceFactory = ({
/*
* Delete organization by id
* */
const deleteOrganizationById = async (userId: string, orgId: string, actorOrgScope?: string) => {
const { membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const deleteOrganizationById = async (userId: string, orgId: string, actorOrgId?: string) => {
const { membership } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
if ((membership.role as OrgMembershipRole) !== OrgMembershipRole.Admin)
throw new UnauthorizedError({ name: "Delete org by id", message: "Not an admin" });
@@ -227,8 +227,8 @@ export const orgServiceFactory = ({
* Org membership management
* Not another service because it has close ties with how an org works doesn't make sense to seperate them
* */
const updateOrgMembership = async ({ role, orgId, userId, membershipId, actorOrgScope }: TUpdateOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const updateOrgMembership = async ({ role, orgId, userId, membershipId, actorOrgId }: TUpdateOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
const isCustomRole = !Object.values(OrgMembershipRole).includes(role as OrgMembershipRole);
@@ -258,16 +258,18 @@ export const orgServiceFactory = ({
/*
* Invite user to organization
*/
const inviteUserToOrganization = async ({ orgId, userId, inviteeEmail, actorOrgScope }: TInviteUserToOrgDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const inviteUserToOrganization = async ({ orgId, userId, inviteeEmail, actorOrgId }: TInviteUserToOrgDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member);
const samlCfg = await samlConfigDAL.findOne({ orgId });
if (samlCfg && samlCfg.isActive) {
const org = await orgDAL.findOrgById(orgId);
if (org?.authEnforced) {
throw new BadRequestError({
message: "Failed to invite member due to SAML SSO configured for organization"
message: "Failed to invite user due to org-level auth enforced for organization"
});
}
const plan = await licenseService.getPlan(orgId);
if (plan.memberLimit !== null && plan.membersUsed >= plan.memberLimit) {
// case: limit imposed on number of members allowed
@@ -338,7 +340,6 @@ export const orgServiceFactory = ({
orgId
});
const org = await orgDAL.findOrgById(orgId);
const user = await userDAL.findById(userId);
const appCfg = getConfig();
await smtpService.sendMail({
@@ -415,8 +416,8 @@ export const orgServiceFactory = ({
return { token, user };
};
const deleteOrgMembership = async ({ orgId, userId, membershipId, actorOrgScope }: TDeleteOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const deleteOrgMembership = async ({ orgId, userId, membershipId, actorOrgId }: TDeleteOrgMembershipDTO) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
const membership = await orgDAL.deleteMembershipById(membershipId, orgId);
@@ -428,15 +429,15 @@ export const orgServiceFactory = ({
/*
* CRUD operations of incident contacts
* */
const findIncidentContacts = async (userId: string, orgId: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const findIncidentContacts = async (userId: string, orgId: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.IncidentAccount);
const incidentContacts = await incidentContactDAL.findByOrgId(orgId);
return incidentContacts;
};
const createIncidentContact = async (userId: string, orgId: string, email: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const createIncidentContact = async (userId: string, orgId: string, email: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.IncidentAccount);
const doesIncidentContactExist = await incidentContactDAL.findOne(orgId, { email });
if (doesIncidentContactExist) {
@@ -450,8 +451,8 @@ export const orgServiceFactory = ({
return incidentContact;
};
const deleteIncidentContact = async (userId: string, orgId: string, id: string, actorOrgScope?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgScope);
const deleteIncidentContact = async (userId: string, orgId: string, id: string, actorOrgId?: string) => {
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.IncidentAccount);
const incidentContact = await incidentContactDAL.deleteById(id, orgId);
+4 -4
View File
@@ -7,20 +7,20 @@ export type TUpdateOrgMembershipDTO = {
orgId: string;
membershipId: string;
role: string;
actorOrgScope?: string;
actorOrgId?: string;
};
export type TDeleteOrgMembershipDTO = {
userId: string;
orgId: string;
membershipId: string;
actorOrgScope?: string;
actorOrgId?: string;
};
export type TInviteUserToOrgDTO = {
userId: string;
orgId: string;
actorOrgScope?: string;
actorOrgId?: string;
inviteeEmail: string;
};
@@ -33,7 +33,7 @@ export type TVerifyUserToOrgDTO = {
export type TFindAllWorkspacesDTO = {
actor: ActorType;
actorId: string;
actorOrgScope?: string;
actorOrgId?: string;
orgId: string;
};