diff --git a/backend/src/ee/services/group/group-service.ts b/backend/src/ee/services/group/group-service.ts index 3dcb7588f..d2e836745 100644 --- a/backend/src/ee/services/group/group-service.ts +++ b/backend/src/ee/services/group/group-service.ts @@ -67,7 +67,7 @@ export const groupServiceFactory = ({ const createGroup = async ({ name, slug, role, actor, actorId, actorAuthMethod, actorOrgId }: TCreateGroupDTO) => { if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" }); - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, actorOrgId, @@ -89,6 +89,7 @@ export const groupServiceFactory = ({ const isCustomRole = Boolean(customRole); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionGroupActions.ManagePrivileges, OrgPermissionSubjects.Groups, permission, @@ -138,13 +139,14 @@ export const groupServiceFactory = ({ }: TUpdateGroupDTO) => { if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" }); - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, actorOrgId, actorAuthMethod, actorOrgId ); + ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups); const plan = await licenseService.getPlan(actorOrgId); @@ -167,6 +169,7 @@ export const groupServiceFactory = ({ const isCustomRole = Boolean(customOrgRole); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionGroupActions.ManagePrivileges, OrgPermissionSubjects.Groups, permission, @@ -313,7 +316,7 @@ export const groupServiceFactory = ({ const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => { if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" }); - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, actorOrgId, @@ -349,11 +352,13 @@ export const groupServiceFactory = ({ // check if user has broader or equal to privileges than group const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionGroupActions.AddMembers, OrgPermissionSubjects.Groups, permission, groupRolePermission ); + if (!permissionBoundary.isValid) throw new ForbiddenRequestError({ name: "PermissionBoundaryError", @@ -389,7 +394,7 @@ export const groupServiceFactory = ({ }: TRemoveUserFromGroupDTO) => { if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" }); - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, actorOrgId, @@ -425,6 +430,7 @@ export const groupServiceFactory = ({ // check if user has broader or equal to privileges than group const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionGroupActions.RemoveMembers, OrgPermissionSubjects.Groups, permission, diff --git a/backend/src/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service.ts b/backend/src/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service.ts index 03bbbd8eb..37c258dc4 100644 --- a/backend/src/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service.ts +++ b/backend/src/ee/services/identity-project-additional-privilege-v2/identity-project-additional-privilege-v2-service.ts @@ -67,7 +67,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ ProjectPermissionIdentityActions.Edit, subject(ProjectPermissionSub.Identity, { identityId }) ); - const { permission: targetIdentityPermission } = await permissionService.getProjectPermission({ + const { permission: targetIdentityPermission, membership } = await permissionService.getProjectPermission({ actor: ActorType.IDENTITY, actorId: identityId, projectId: identityProjectMembership.projectId, @@ -80,6 +80,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetIdentityPermission.update(targetIdentityPermission.rules.concat(customPermission)); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, @@ -158,7 +159,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ ProjectPermissionIdentityActions.Edit, subject(ProjectPermissionSub.Identity, { identityId: identityProjectMembership.identityId }) ); - const { permission: targetIdentityPermission } = await permissionService.getProjectPermission({ + const { permission: targetIdentityPermission, membership } = await permissionService.getProjectPermission({ actor: ActorType.IDENTITY, actorId: identityProjectMembership.identityId, projectId: identityProjectMembership.projectId, @@ -171,6 +172,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetIdentityPermission.update(targetIdentityPermission.rules.concat(data.permissions || [])); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, @@ -237,7 +239,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ message: `Failed to find identity with membership ${identityPrivilege.projectMembershipId}` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId: identityProjectMembership.projectId, @@ -258,6 +260,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({ actionProjectType: ActionProjectType.Any }); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, diff --git a/backend/src/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service.ts b/backend/src/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service.ts index 513a933bf..6d603d664 100644 --- a/backend/src/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service.ts +++ b/backend/src/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service.ts @@ -67,7 +67,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ if (!identityProjectMembership) throw new NotFoundError({ message: `Failed to find identity with id ${identityId}` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId: identityProjectMembership.projectId, @@ -94,6 +94,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetIdentityPermission.update(targetIdentityPermission.rules.concat(customPermission)); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, @@ -160,7 +161,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ if (!identityProjectMembership) throw new NotFoundError({ message: `Failed to find identity with id ${identityId}` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId: identityProjectMembership.projectId, @@ -187,6 +188,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetIdentityPermission.update(targetIdentityPermission.rules.concat(data.permissions || [])); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, @@ -270,7 +272,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ if (!identityProjectMembership) throw new NotFoundError({ message: `Failed to find identity with id ${identityId}` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId: identityProjectMembership.projectId, @@ -292,6 +294,7 @@ export const identityProjectAdditionalPrivilegeServiceFactory = ({ actionProjectType: ActionProjectType.Any }); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, diff --git a/backend/src/ee/services/permission/permission-dal.ts b/backend/src/ee/services/permission/permission-dal.ts index ca46442e9..9b23d6113 100644 --- a/backend/src/ee/services/permission/permission-dal.ts +++ b/backend/src/ee/services/permission/permission-dal.ts @@ -49,6 +49,7 @@ export const permissionDALFactory = (db: TDbClient) => { .join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`) .select( selectAllTableCols(TableName.OrgMembership), + db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization), db.ref("slug").withSchema(TableName.OrgRoles).withSchema(TableName.OrgRoles).as("customRoleSlug"), db.ref("permissions").withSchema(TableName.OrgRoles), db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"), @@ -70,7 +71,8 @@ export const permissionDALFactory = (db: TDbClient) => { OrgMembershipsSchema.extend({ permissions: z.unknown(), orgAuthEnforced: z.boolean().optional().nullable(), - customRoleSlug: z.string().optional().nullable() + customRoleSlug: z.string().optional().nullable(), + shouldUseNewPrivilegeSystem: z.boolean() }).parse(el), childrenMapper: [ { @@ -118,7 +120,9 @@ export const permissionDALFactory = (db: TDbClient) => { .select(selectAllTableCols(TableName.IdentityOrgMembership)) .select(db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced")) .select("permissions") + .select(db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization)) .first(); + return membership; } catch (error) { throw new DatabaseError({ error, name: "GetOrgIdentityPermission" }); @@ -668,7 +672,8 @@ export const permissionDALFactory = (db: TDbClient) => { db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"), db.ref("orgId").withSchema(TableName.Project), db.ref("type").withSchema(TableName.Project).as("projectType"), - db.ref("id").withSchema(TableName.Project).as("projectId") + db.ref("id").withSchema(TableName.Project).as("projectId"), + db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization) ); const [userPermission] = sqlNestRelationships({ @@ -684,7 +689,8 @@ export const permissionDALFactory = (db: TDbClient) => { groupMembershipCreatedAt, groupMembershipUpdatedAt, membershipUpdatedAt, - projectType + projectType, + shouldUseNewPrivilegeSystem }) => ({ orgId, orgAuthEnforced, @@ -694,7 +700,8 @@ export const permissionDALFactory = (db: TDbClient) => { projectType, id: membershipId || groupMembershipId, createdAt: membershipCreatedAt || groupMembershipCreatedAt, - updatedAt: membershipUpdatedAt || groupMembershipUpdatedAt + updatedAt: membershipUpdatedAt || groupMembershipUpdatedAt, + shouldUseNewPrivilegeSystem }), childrenMapper: [ { @@ -995,6 +1002,7 @@ export const permissionDALFactory = (db: TDbClient) => { `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id` ) + .join(TableName.Organization, `${TableName.Project}.orgId`, `${TableName.Organization}.id`) .leftJoin(TableName.IdentityMetadata, (queryBuilder) => { void queryBuilder .on(`${TableName.Identity}.id`, `${TableName.IdentityMetadata}.identityId`) @@ -1012,6 +1020,7 @@ export const permissionDALFactory = (db: TDbClient) => { db.ref("updatedAt").withSchema(TableName.IdentityProjectMembership).as("membershipUpdatedAt"), db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"), db.ref("permissions").withSchema(TableName.ProjectRoles), + db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization), db.ref("id").withSchema(TableName.IdentityProjectAdditionalPrivilege).as("identityApId"), db.ref("permissions").withSchema(TableName.IdentityProjectAdditionalPrivilege).as("identityApPermissions"), db @@ -1045,7 +1054,8 @@ export const permissionDALFactory = (db: TDbClient) => { membershipUpdatedAt, orgId, identityName, - projectType + projectType, + shouldUseNewPrivilegeSystem }) => ({ id: membershipId, identityId, @@ -1055,6 +1065,7 @@ export const permissionDALFactory = (db: TDbClient) => { updatedAt: membershipUpdatedAt, orgId, projectType, + shouldUseNewPrivilegeSystem, // just a prefilled value orgAuthEnforced: false }), diff --git a/backend/src/ee/services/permission/permission-fns.ts b/backend/src/ee/services/permission/permission-fns.ts index 3c88fd12d..a0a94c352 100644 --- a/backend/src/ee/services/permission/permission-fns.ts +++ b/backend/src/ee/services/permission/permission-fns.ts @@ -152,16 +152,28 @@ const escapeHandlebarsMissingMetadata = (obj: Record) => { // the new privilege management system is based on the actor having the appropriate permission to perform the privilege change, // regardless of the actor's privilege level. const validatePrivilegeChangeOperation = ( + shouldUseNewPrivilegeSystem: boolean, opAction: OrgPermissionSet[0] | ProjectPermissionSet[0], opSubject: OrgPermissionSet[1] | ProjectPermissionSet[1], actorPermission: MongoAbility, managedPermission: MongoAbility ) => { - // first we ensure if the actor has the permission to manage the privilege - if (actorPermission.can(opAction, opSubject)) { + if (shouldUseNewPrivilegeSystem) { + if (actorPermission.can(opAction, opSubject)) { + return { + isValid: true, + missingPermissions: [] + }; + } + return { - isValid: true, - missingPermissions: [] + isValid: false, + missingPermissions: [ + { + action: opAction, + subject: opSubject + } + ] }; } diff --git a/backend/src/ee/services/permission/permission-service.ts b/backend/src/ee/services/permission/permission-service.ts index ddaf55d9d..2997dcf74 100644 --- a/backend/src/ee/services/permission/permission-service.ts +++ b/backend/src/ee/services/permission/permission-service.ts @@ -390,14 +390,18 @@ export const permissionServiceFactory = ({ const scopes = ServiceTokenScopes.parse(serviceToken.scopes || []); return { permission: buildServiceTokenProjectPermission(scopes, serviceToken.permissions), - membership: undefined + membership: { + shouldUseNewPrivilegeSystem: true + } }; }; type TProjectPermissionRT = T extends ActorType.SERVICE ? { permission: MongoAbility; - membership: undefined; + membership: { + shouldUseNewPrivilegeSystem: boolean; + }; hasRole: (arg: string) => boolean; } // service token doesn't have both membership and roles : { @@ -406,6 +410,7 @@ export const permissionServiceFactory = ({ orgAuthEnforced: boolean | null | undefined; orgId: string; roles: Array<{ role: string }>; + shouldUseNewPrivilegeSystem: boolean; }; hasRole: (role: string) => boolean; }; diff --git a/backend/src/ee/services/project-user-additional-privilege/project-user-additional-privilege-service.ts b/backend/src/ee/services/project-user-additional-privilege/project-user-additional-privilege-service.ts index 167ce0964..c6a1ac835 100644 --- a/backend/src/ee/services/project-user-additional-privilege/project-user-additional-privilege-service.ts +++ b/backend/src/ee/services/project-user-additional-privilege/project-user-additional-privilege-service.ts @@ -68,7 +68,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({ actionProjectType: ActionProjectType.Any }); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Edit, ProjectPermissionSub.Member); - const { permission: targetUserPermission } = await permissionService.getProjectPermission({ + const { permission: targetUserPermission, membership } = await permissionService.getProjectPermission({ actor: ActorType.USER, actorId: projectMembership.userId, projectId: projectMembership.projectId, @@ -81,6 +81,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetUserPermission.update(targetUserPermission.rules.concat(customPermission)); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionMemberActions.ManagePrivileges, ProjectPermissionSub.Member, permission, @@ -155,7 +156,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({ message: `Project membership for user with ID '${userPrivilege.userId}' not found in project with ID '${userPrivilege.projectId}'` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId: projectMembership.projectId, @@ -177,6 +178,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({ // @ts-expect-error this is expected error because of one being really accurate rule definition other being a bit more broader. Both are valid casl rules targetUserPermission.update(targetUserPermission.rules.concat(dto.permissions || [])); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionMemberActions.ManagePrivileges, ProjectPermissionSub.Member, permission, diff --git a/backend/src/services/group-project/group-project-service.ts b/backend/src/services/group-project/group-project-service.ts index 445141540..37ffacfa5 100644 --- a/backend/src/services/group-project/group-project-service.ts +++ b/backend/src/services/group-project/group-project-service.ts @@ -70,7 +70,7 @@ export const groupProjectServiceFactory = ({ if (!project) throw new NotFoundError({ message: `Failed to find project with ID ${projectId}` }); if (project.version < 2) throw new BadRequestError({ message: `Failed to add group to E2EE project` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -103,6 +103,7 @@ export const groupProjectServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionGroupActions.ManagePrivileges, ProjectPermissionSub.Groups, permission, @@ -253,7 +254,7 @@ export const groupProjectServiceFactory = ({ if (!project) throw new NotFoundError({ message: `Failed to find project with ID ${projectId}` }); - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -275,6 +276,7 @@ export const groupProjectServiceFactory = ({ project.id ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionGroupActions.ManagePrivileges, ProjectPermissionSub.Groups, permission, diff --git a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts index a11fa64ea..f80b1b2c3 100644 --- a/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts +++ b/backend/src/services/identity-aws-auth/identity-aws-auth-service.ts @@ -322,7 +322,7 @@ export const identityAwsAuthServiceFactory = ({ message: "The identity does not have aws auth" }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -340,11 +340,13 @@ export const identityAwsAuthServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, rolePermission ); + if (!permissionBoundary.isValid) throw new ForbiddenRequestError({ name: "PermissionBoundaryError", diff --git a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts index 2e7013852..56249c606 100644 --- a/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts +++ b/backend/src/services/identity-azure-auth/identity-azure-auth-service.ts @@ -296,7 +296,7 @@ export const identityAzureAuthServiceFactory = ({ message: "The identity does not have azure auth" }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -313,6 +313,7 @@ export const identityAzureAuthServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts index cf8812980..11c5151e9 100644 --- a/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts +++ b/backend/src/services/identity-gcp-auth/identity-gcp-auth-service.ts @@ -342,7 +342,7 @@ export const identityGcpAuthServiceFactory = ({ message: "The identity does not have gcp auth" }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -359,6 +359,7 @@ export const identityGcpAuthServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity-jwt-auth/identity-jwt-auth-service.ts b/backend/src/services/identity-jwt-auth/identity-jwt-auth-service.ts index a3b3842dd..353d1e46f 100644 --- a/backend/src/services/identity-jwt-auth/identity-jwt-auth-service.ts +++ b/backend/src/services/identity-jwt-auth/identity-jwt-auth-service.ts @@ -498,7 +498,7 @@ export const identityJwtAuthServiceFactory = ({ }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -517,6 +517,7 @@ export const identityJwtAuthServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 4a6467af5..bc7dda22e 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -471,7 +471,7 @@ export const identityKubernetesAuthServiceFactory = ({ message: "The identity does not have kubernetes auth" }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -488,6 +488,7 @@ export const identityKubernetesAuthServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts b/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts index f8deb63c7..bb0077664 100644 --- a/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts +++ b/backend/src/services/identity-oidc-auth/identity-oidc-auth-service.ts @@ -410,7 +410,7 @@ export const identityOidcAuthServiceFactory = ({ }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -429,11 +429,13 @@ export const identityOidcAuthServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, rolePermission ); + if (!permissionBoundary.isValid) throw new ForbiddenRequestError({ name: "PermissionBoundaryError", diff --git a/backend/src/services/identity-project/identity-project-service.ts b/backend/src/services/identity-project/identity-project-service.ts index cabed7751..ae7f8f25b 100644 --- a/backend/src/services/identity-project/identity-project-service.ts +++ b/backend/src/services/identity-project/identity-project-service.ts @@ -53,7 +53,7 @@ export const identityProjectServiceFactory = ({ projectId, roles }: TCreateProjectIdentityDTO) => { - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -91,6 +91,7 @@ export const identityProjectServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, @@ -166,7 +167,7 @@ export const identityProjectServiceFactory = ({ actorAuthMethod, actorOrgId }: TUpdateProjectIdentityDTO) => { - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -192,11 +193,13 @@ export const identityProjectServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionIdentityActions.ManagePrivileges, ProjectPermissionSub.Identity, permission, rolePermission ); + if (!permissionBoundary.isValid) throw new ForbiddenRequestError({ name: "PermissionBoundaryError", diff --git a/backend/src/services/identity-token-auth/identity-token-auth-service.ts b/backend/src/services/identity-token-auth/identity-token-auth-service.ts index 4dcba6910..ab2216458 100644 --- a/backend/src/services/identity-token-auth/identity-token-auth-service.ts +++ b/backend/src/services/identity-token-auth/identity-token-auth-service.ts @@ -237,7 +237,7 @@ export const identityTokenAuthServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); - const { permission: rolePermission } = await permissionService.getOrgPermission( + const { permission: rolePermission, membership } = await permissionService.getOrgPermission( ActorType.IDENTITY, identityMembershipOrg.identityId, identityMembershipOrg.orgId, @@ -246,6 +246,7 @@ export const identityTokenAuthServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, @@ -295,7 +296,7 @@ export const identityTokenAuthServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); - const { permission: rolePermission } = await permissionService.getOrgPermission( + const { permission: rolePermission, membership } = await permissionService.getOrgPermission( ActorType.IDENTITY, identityMembershipOrg.identityId, identityMembershipOrg.orgId, @@ -304,6 +305,7 @@ export const identityTokenAuthServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.CreateToken, OrgPermissionSubjects.Identity, permission, @@ -423,7 +425,7 @@ export const identityTokenAuthServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); - const { permission: rolePermission } = await permissionService.getOrgPermission( + const { permission: rolePermission, membership } = await permissionService.getOrgPermission( ActorType.IDENTITY, identityMembershipOrg.identityId, identityMembershipOrg.orgId, @@ -431,6 +433,7 @@ export const identityTokenAuthServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.CreateToken, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity-ua/identity-ua-service.ts b/backend/src/services/identity-ua/identity-ua-service.ts index 77e6ad3f3..0c067e057 100644 --- a/backend/src/services/identity-ua/identity-ua-service.ts +++ b/backend/src/services/identity-ua/identity-ua-service.ts @@ -360,7 +360,7 @@ export const identityUaServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity); - const { permission: rolePermission } = await permissionService.getOrgPermission( + const { permission: rolePermission, membership } = await permissionService.getOrgPermission( ActorType.IDENTITY, identityMembershipOrg.identityId, identityMembershipOrg.orgId, @@ -368,6 +368,7 @@ export const identityUaServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.RevokeAuth, OrgPermissionSubjects.Identity, permission, @@ -406,7 +407,7 @@ export const identityUaServiceFactory = ({ }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -423,6 +424,7 @@ export const identityUaServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.CreateToken, OrgPermissionSubjects.Identity, permission, @@ -473,7 +475,7 @@ export const identityUaServiceFactory = ({ message: "The identity does not have universal auth" }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -491,6 +493,7 @@ export const identityUaServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.GetToken, OrgPermissionSubjects.Identity, permission, @@ -531,7 +534,7 @@ export const identityUaServiceFactory = ({ }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -548,6 +551,7 @@ export const identityUaServiceFactory = ({ actorOrgId ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.GetToken, OrgPermissionSubjects.Identity, permission, @@ -581,7 +585,7 @@ export const identityUaServiceFactory = ({ }); } - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityMembershipOrg.orgId, @@ -599,6 +603,7 @@ export const identityUaServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.DeleteToken, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 41252bf25..937fba6f7 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -49,7 +49,13 @@ export const identityServiceFactory = ({ actorOrgId, metadata }: TCreateIdentityDTO) => { - const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId); + const { permission, membership } = await permissionService.getOrgPermission( + actor, + actorId, + orgId, + actorAuthMethod, + actorOrgId + ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity); const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole( @@ -58,6 +64,7 @@ export const identityServiceFactory = ({ ); const isCustomRole = Boolean(customRole); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.ManagePrivileges, OrgPermissionSubjects.Identity, permission, @@ -121,7 +128,7 @@ export const identityServiceFactory = ({ const identityOrgMembership = await identityOrgMembershipDAL.findOne({ identityId: id }); if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` }); - const { permission } = await permissionService.getOrgPermission( + const { permission, membership } = await permissionService.getOrgPermission( actor, actorId, identityOrgMembership.orgId, @@ -139,6 +146,7 @@ export const identityServiceFactory = ({ const isCustomRole = Boolean(customOrgRole); const appliedRolePermissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, OrgPermissionIdentityActions.ManagePrivileges, OrgPermissionSubjects.Identity, permission, diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index b89b6f7fa..63aaa2457 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -291,7 +291,7 @@ export const orgServiceFactory = ({ }: TUpgradePrivilegeSystemDTO) => { const { membership } = await permissionService.getUserOrgPermission(actorId, orgId, actorAuthMethod, actorOrgId); - if (membership.role != OrgMembershipRole.Admin) { + if (membership.role !== OrgMembershipRole.Admin) { throw new ForbiddenRequestError({ message: "Insufficient privileges - only the organization admin can upgrade the privilege system." }); @@ -881,7 +881,7 @@ export const orgServiceFactory = ({ // if there exist no project membership we set is as given by the request for await (const project of projectsToInvite) { const projectId = project.id; - const { permission: projectPermission } = await permissionService.getProjectPermission({ + const { permission: projectPermission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -920,6 +920,7 @@ export const orgServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionMemberActions.ManagePrivileges, ProjectPermissionSub.Member, projectPermission, diff --git a/backend/src/services/project-membership/project-membership-service.ts b/backend/src/services/project-membership/project-membership-service.ts index ecc7f83d0..62668ed77 100644 --- a/backend/src/services/project-membership/project-membership-service.ts +++ b/backend/src/services/project-membership/project-membership-service.ts @@ -253,7 +253,7 @@ export const projectMembershipServiceFactory = ({ membershipId, roles }: TUpdateProjectMembershipDTO) => { - const { permission } = await permissionService.getProjectPermission({ + const { permission, membership } = await permissionService.getProjectPermission({ actor, actorId, projectId, @@ -275,6 +275,7 @@ export const projectMembershipServiceFactory = ({ ); const permissionBoundary = validatePrivilegeChangeOperation( + membership.shouldUseNewPrivilegeSystem, ProjectPermissionMemberActions.ManagePrivileges, ProjectPermissionSub.Member, permission,