diff --git a/backend/src/db/migrations/20240702131735_secret-approval-groups.ts b/backend/src/db/migrations/20240702131735_secret-approval-groups.ts index 84824ac65..c1b6bb48b 100644 --- a/backend/src/db/migrations/20240702131735_secret-approval-groups.ts +++ b/backend/src/db/migrations/20240702131735_secret-approval-groups.ts @@ -127,7 +127,8 @@ export async function down(knex: Knex): Promise { }); await knex.schema.alterTable(TableName.SecretApprovalPolicyApprover, (tb) => { tb.dropColumn("approverUserId"); - tb.uuid("approverId").notNullable().alter(); + // akhilmhdh: i had to comment this out and is not possible as membership is now changed in structure + // tb.uuid("approverId").notNullable().alter(); }); } } diff --git a/backend/src/ee/services/permission/permission-dal.ts b/backend/src/ee/services/permission/permission-dal.ts index 4841eed3d..d0921e5f7 100644 --- a/backend/src/ee/services/permission/permission-dal.ts +++ b/backend/src/ee/services/permission/permission-dal.ts @@ -16,6 +16,9 @@ import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; import { ActorType } from "@app/services/auth/auth-type"; interface TPermissionDataReturn extends TMemberships { + orgAuthEnforced?: boolean | null; + orgGoogleSsoAuthEnforced?: boolean | null; + bypassOrgAuthEnabled?: boolean | null; roles: { id: string; createdAt: Date; @@ -177,6 +180,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { const docs = await (tx || db) .replicaNode()(TableName.Membership) .join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`) + .join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`) .leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`) .leftJoin(TableName.AdditionalPrivilege, (qb) => { if (actorType === ActorType.IDENTITY) { @@ -264,13 +268,22 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => { db.ref("updatedAt").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeUpdatedAt"), db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"), db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"), - db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue") + db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue"), + db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization), + db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"), + db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"), + db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled") ); const data = sqlNestRelationships({ data: docs, key: "id", - parentMapper: (el) => MembershipsSchema.parse(el), + parentMapper: (el) => + MembershipsSchema.extend({ + orgAuthEnforced: z.boolean().optional().nullable(), + orgGoogleSsoAuthEnforced: z.boolean(), + bypassOrgAuthEnabled: z.boolean() + }).parse(el), childrenMapper: [ { key: "additionalPrivilegeId", diff --git a/backend/src/ee/services/permission/permission-fns.ts b/backend/src/ee/services/permission/permission-fns.ts index 7d61d7499..0da5ad3b2 100644 --- a/backend/src/ee/services/permission/permission-fns.ts +++ b/backend/src/ee/services/permission/permission-fns.ts @@ -2,7 +2,7 @@ import { ForbiddenError, MongoAbility, PureAbility, subject } from "@casl/ability"; import { z } from "zod"; -import { OrgMembershipRole, TOrganizations } from "@app/db/schemas"; +import { TOrganizations } from "@app/db/schemas"; import { validatePermissionBoundary } from "@app/lib/casl/boundary"; import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; import { ActorAuthMethod, AuthMethod } from "@app/services/auth/auth-type"; @@ -123,13 +123,13 @@ function validateOrgSSO( isOrgSsoEnforced: TOrganizations["authEnforced"], isOrgGoogleSsoEnforced: TOrganizations["googleSsoAuthEnforced"], isOrgSsoBypassEnabled: TOrganizations["bypassOrgAuthEnabled"], - orgRole: OrgMembershipRole + isAdmin: boolean ) { if (actorAuthMethod === undefined) { throw new UnauthorizedError({ name: "No auth method defined" }); } - if ((isOrgSsoEnforced || isOrgGoogleSsoEnforced) && isOrgSsoBypassEnabled && orgRole === OrgMembershipRole.Admin) { + if ((isOrgSsoEnforced || isOrgGoogleSsoEnforced) && isOrgSsoBypassEnabled && isAdmin) { return; } diff --git a/backend/src/ee/services/permission/permission-service.ts b/backend/src/ee/services/permission/permission-service.ts index a1b6bc7ce..c227eb6ba 100644 --- a/backend/src/ee/services/permission/permission-service.ts +++ b/backend/src/ee/services/permission/permission-service.ts @@ -32,7 +32,7 @@ import { TUserDALFactory } from "@app/services/user/user-dal"; import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission"; import { TPermissionDALFactory } from "./permission-dal"; -import { escapeHandlebarsMissingDict } from "./permission-fns"; +import { escapeHandlebarsMissingDict, validateOrgSSO } from "./permission-fns"; import { TBuildOrgPermissionDTO, TBuildProjectPermissionDTO, @@ -223,24 +223,25 @@ export const permissionServiceFactory = ({ return activeRoles.concat(activeAdditionalPrivileges); }); + const hasRole = (role: string) => + permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role))); + + validateOrgSSO( + authMethod, + permissionData?.[0].orgAuthEnforced, + Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced), + Boolean(permissionData?.[0].bypassOrgAuthEnabled), + hasRole(OrgMembershipRole.Admin) + ); + const permission = createMongoAbility(buildOrgPermissionRules(permissionFromRoles), { conditionsMatcher }); - // TODO(simp): validate this - // validateOrgSSO( - // authMethod, - // membership.orgAuthEnforced, - // membership.orgGoogleSsoAuthEnforced, - // membership.bypassOrgAuthEnabled, - // membership.role as OrgMembershipRole - // ); - return { permission, memberships: permissionData, - hasRole: (role: string) => - permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role))) + hasRole }; }; @@ -367,13 +368,16 @@ export const permissionServiceFactory = ({ return activeRoles.concat(activeAdditionalPrivileges); }); - // validateOrgSSO( - // authMethod, - // userProjectPermission.orgAuthEnforced, - // userProjectPermission.orgGoogleSsoAuthEnforced, - // userProjectPermission.bypassOrgAuthEnabled, - // userProjectPermission.orgRole - // ); + const hasRole = (role: string) => + permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role))); + + validateOrgSSO( + actorAuthMethod, + permissionData?.[0].orgAuthEnforced, + Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced), + Boolean(permissionData?.[0].bypassOrgAuthEnabled), + hasRole(ProjectMembershipRole.Admin) + ); const rules = buildProjectPermissionRules(permissionFromRoles); const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false }); @@ -422,8 +426,7 @@ export const permissionServiceFactory = ({ return { permission, memberships: permissionData, - hasRole: (role: string) => - permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role))) + hasRole }; }; diff --git a/backend/src/ee/services/scim/scim-service.ts b/backend/src/ee/services/scim/scim-service.ts index 32e5f18be..14a83d1f9 100644 --- a/backend/src/ee/services/scim/scim-service.ts +++ b/backend/src/ee/services/scim/scim-service.ts @@ -19,6 +19,7 @@ import { getConfig } from "@app/lib/config/env"; import { crypto } from "@app/lib/crypto"; import { BadRequestError, NotFoundError, ScimRequestError, UnauthorizedError } from "@app/lib/errors"; import { alphaNumericNanoId } from "@app/lib/nanoid"; +import { TAdditionalPrivilegeDALFactory } from "@app/services/additional-privilege/additional-privilege-dal"; import { AuthTokenType } from "@app/services/auth/auth-type"; import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal"; import { TMembershipRoleDALFactory } from "@app/services/membership/membership-role-dal"; @@ -93,6 +94,7 @@ type TScimServiceFactoryDep = { permissionService: Pick; smtpService: Pick; externalGroupOrgRoleMappingDAL: TExternalGroupOrgRoleMappingDALFactory; + additionalPrivilegeDAL: TAdditionalPrivilegeDALFactory; }; export const scimServiceFactory = ({ @@ -111,7 +113,8 @@ export const scimServiceFactory = ({ externalGroupOrgRoleMappingDAL, membershipGroupDAL, membershipUserDAL, - membershipRoleDAL + membershipRoleDAL, + additionalPrivilegeDAL }: TScimServiceFactoryDep): TScimServiceFactory => { const createScimToken: TScimServiceFactory["createScimToken"] = async ({ actor, @@ -673,7 +676,8 @@ export const scimServiceFactory = ({ licenseService, membershipUserDAL, membershipRoleDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }); return {}; // intentionally return empty object upon success diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 016f692da..9534ca8b0 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -575,7 +575,8 @@ export const registerRoutes = async ( smtpService, tokenService, userAliasDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }); const membershipIdentityService = membershipIdentityServiceFactory({ @@ -583,7 +584,8 @@ export const registerRoutes = async ( membershipRoleDAL, orgDAL, permissionService, - roleDAL + roleDAL, + additionalPrivilegeDAL }); const membershipGroupService = membershipGroupServiceFactory({ @@ -599,7 +601,8 @@ export const registerRoutes = async ( roleDAL, projectDAL, identityDAL, - userDAL + userDAL, + externalGroupOrgRoleMappingDAL }); const additionalPrivilegeService = additionalPrivilegeServiceFactory({ additionalPrivilegeDAL, @@ -764,7 +767,8 @@ export const registerRoutes = async ( groupDAL, membershipGroupDAL, membershipRoleDAL, - membershipUserDAL + membershipUserDAL, + additionalPrivilegeDAL }); const githubOrgSyncConfigService = githubOrgSyncServiceFactory({ @@ -891,7 +895,8 @@ export const registerRoutes = async ( membershipRoleDAL, membershipUserDAL, roleDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }); const signupService = authSignupServiceFactory({ tokenService, diff --git a/backend/src/server/routes/v1/project-membership-router.ts b/backend/src/server/routes/v1/project-membership-router.ts index 33e143d2a..57fdad031 100644 --- a/backend/src/server/routes/v1/project-membership-router.ts +++ b/backend/src/server/routes/v1/project-membership-router.ts @@ -161,7 +161,6 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider } }); - // TODO(simp): look into multi deletion and this as well server.route({ method: "POST", url: "/:projectId/memberships/details", diff --git a/backend/src/services/identity/identity-service.ts b/backend/src/services/identity/identity-service.ts index 3bad42b75..721844070 100644 --- a/backend/src/services/identity/identity-service.ts +++ b/backend/src/services/identity/identity-service.ts @@ -273,7 +273,7 @@ export const identityServiceFactory = ({ ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity); - // TODO(simp): check this in identity service + // TODO(namespace): check this in identity service const activeLockouts = await keyStore.getKeysByPattern(`lockout:identity:${id}:*`); const activeLockoutAuthMethods = new Set(); diff --git a/backend/src/services/membership-identity/membership-identity-service.ts b/backend/src/services/membership-identity/membership-identity-service.ts index f1530fc29..3be894c2c 100644 --- a/backend/src/services/membership-identity/membership-identity-service.ts +++ b/backend/src/services/membership-identity/membership-identity-service.ts @@ -5,6 +5,7 @@ import { groupBy } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; import { SearchResourceOperators } from "@app/lib/search-resource/search"; +import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { TMembershipRoleDALFactory } from "../membership/membership-role-dal"; import { TOrgDALFactory } from "../org/org-dal"; import { TRoleDALFactory } from "../role/role-dal"; @@ -29,6 +30,7 @@ type TMembershipIdentityServiceFactoryDep = { "getOrgPermission" | "getProjectPermission" | "getProjectPermissionByRoles" | "getOrgPermissionByRoles" >; orgDAL: Pick; + additionalPrivilegeDAL: Pick; }; export type TMembershipIdentityServiceFactory = ReturnType; @@ -38,7 +40,8 @@ export const membershipIdentityServiceFactory = ({ roleDAL, membershipRoleDAL, permissionService, - orgDAL + orgDAL, + additionalPrivilegeDAL }: TMembershipIdentityServiceFactoryDep) => { const scopeFactory = { [AccessScope.Organization]: newOrgMembershipIdentityFactory({ @@ -255,6 +258,7 @@ export const membershipIdentityServiceFactory = ({ await factory.onDeleteMembershipIdentityGuard(dto); + const scopeField = factory.getScopeField(scopeData); const scopeDatabaseFields = factory.getScopeDatabaseFields(dto.scopeData); const existingMembership = await membershipIdentityDAL.findOne({ scope: scopeData.scope, @@ -272,6 +276,13 @@ export const membershipIdentityServiceFactory = ({ }); const membershipDoc = await membershipIdentityDAL.transaction(async (tx) => { + await additionalPrivilegeDAL.delete( + { + actorIdentityId: dto.selector.identityId, + [scopeField.key]: scopeField.value + }, + tx + ); await membershipRoleDAL.delete({ membershipId: existingMembership.id }, tx); const doc = await membershipIdentityDAL.deleteById(existingMembership.id, tx); return doc; diff --git a/backend/src/services/membership-user/membership-user-service.ts b/backend/src/services/membership-user/membership-user-service.ts index 18ad1f5d6..5fd2a2b25 100644 --- a/backend/src/services/membership-user/membership-user-service.ts +++ b/backend/src/services/membership-user/membership-user-service.ts @@ -13,6 +13,7 @@ import { groupBy } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; import { SearchResourceOperators } from "@app/lib/search-resource/search"; +import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { AuthMethod } from "../auth/auth-type"; import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service"; import { TMembershipRoleDALFactory } from "../membership/membership-role-dal"; @@ -53,6 +54,7 @@ type TMembershipUserServiceFactoryDep = { tokenService: TAuthTokenServiceFactory; userGroupMembershipDAL: TUserGroupMembershipDALFactory; projectDAL: TProjectDALFactory; + additionalPrivilegeDAL: TAdditionalPrivilegeDALFactory; }; export type TMembershipUserServiceFactory = ReturnType; @@ -70,7 +72,8 @@ export const membershipUserServiceFactory = ({ smtpService, tokenService, userGroupMembershipDAL, - projectDAL + projectDAL, + additionalPrivilegeDAL }: TMembershipUserServiceFactoryDep) => { const scopeFactory = { [AccessScope.Organization]: newOrgMembershipUserFactory({ @@ -410,11 +413,22 @@ export const membershipUserServiceFactory = ({ userId: dto.permission.id, membershipUserDAL, userGroupMembershipDAL, - membershipRoleDAL + membershipRoleDAL, + additionalPrivilegeDAL }); return doc; } + if (dto.scopeData.scope === AccessScope.Project) { + await additionalPrivilegeDAL.delete( + { + actorUserId: dto.selector.userId, + projectId: dto.scopeData.projectId + }, + tx + ); + } + await membershipRoleDAL.delete({ membershipId: existingMembership.id }, tx); const doc = await membershipUserDAL.deleteById(existingMembership.id, tx); return doc; diff --git a/backend/src/services/org/org-fns.ts b/backend/src/services/org/org-fns.ts index d1a378c33..78d52e816 100644 --- a/backend/src/services/org/org-fns.ts +++ b/backend/src/services/org/org-fns.ts @@ -6,6 +6,7 @@ import { TOrgDALFactory } from "@app/services/org/org-dal"; import { TProjectKeyDALFactory } from "@app/services/project-key/project-key-dal"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; +import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { TMembershipRoleDALFactory } from "../membership/membership-role-dal"; import { TMembershipUserDALFactory } from "../membership-user/membership-user-dal"; @@ -20,6 +21,7 @@ type TDeleteOrgMemberships = { userAliasDAL: Pick; licenseService: Pick; userId?: string; + additionalPrivilegeDAL: Pick; }; export const deleteOrgMembershipsFn = async ({ @@ -32,7 +34,8 @@ export const deleteOrgMembershipsFn = async ({ userId, membershipUserDAL, userGroupMembershipDAL, - membershipRoleDAL + membershipRoleDAL, + additionalPrivilegeDAL }: TDeleteOrgMemberships) => { const deletedMemberships = await orgDAL.transaction(async (tx) => { await membershipRoleDAL.delete( @@ -112,6 +115,16 @@ export const deleteOrgMembershipsFn = async ({ .filter((el) => el.scope === AccessScope.Project && el.scopeProjectId) .map((el) => el.scopeProjectId as string); + await additionalPrivilegeDAL.delete( + { + $in: { + projectId: projectIds, + actorUserId: membershipUserIds + } + }, + tx + ); + // Delete all the project keys of the user in the organization await projectKeyDAL.delete( { diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 180ae4733..fd8f1f7cd 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -36,6 +36,7 @@ import { getDefaultOrgMembershipRoleForUpdateOrg } from "@app/services/org/org-r import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; +import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal"; import { TAuthLoginFactory } from "../auth/auth-login-service"; import { ActorAuthMethod, ActorType, AuthMethod, AuthModeJwtTokenPayload, AuthTokenType } from "../auth/auth-type"; import { TAuthTokenServiceFactory } from "../auth-token/auth-token-service"; @@ -112,6 +113,7 @@ type TOrgServiceFactoryDep = { loginService: Pick; reminderService: Pick; userGroupMembershipDAL: TUserGroupMembershipDALFactory; + additionalPrivilegeDAL: TAdditionalPrivilegeDALFactory; }; export type TOrgServiceFactory = ReturnType; @@ -144,7 +146,8 @@ export const orgServiceFactory = ({ reminderService, membershipRoleDAL, membershipUserDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }: TOrgServiceFactoryDep) => { /* * Get organization details by the organization id @@ -1004,7 +1007,8 @@ export const orgServiceFactory = ({ userId, membershipUserDAL, membershipRoleDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }); return deletedMembership; @@ -1040,7 +1044,8 @@ export const orgServiceFactory = ({ userId, membershipUserDAL, membershipRoleDAL, - userGroupMembershipDAL + userGroupMembershipDAL, + additionalPrivilegeDAL }); return deletedMemberships; diff --git a/backend/src/services/role/org/org-role-factory.ts b/backend/src/services/role/org/org-role-factory.ts index 44fda1991..b2dd469c6 100644 --- a/backend/src/services/role/org/org-role-factory.ts +++ b/backend/src/services/role/org/org-role-factory.ts @@ -10,6 +10,7 @@ import { } from "@app/ee/services/permission/org-permission"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types"; import { BadRequestError } from "@app/lib/errors"; +import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal"; import { isCustomOrgRole } from "@app/services/org/org-role-fns"; import { TRoleScopeFactory } from "../role-types"; @@ -17,9 +18,13 @@ import { TRoleScopeFactory } from "../role-types"; // TODO(simp): missing external group checking type TOrgRoleScopeFactoryDep = { permissionService: Pick; + externalGroupOrgRoleMappingDAL: Pick; }; -export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep): TRoleScopeFactory => { +export const newOrgRoleFactory = ({ + permissionService, + externalGroupOrgRoleMappingDAL +}: TOrgRoleScopeFactoryDep): TRoleScopeFactory => { const getScopeField: TRoleScopeFactory["getScopeField"] = (dto) => { if (dto.scope === AccessScope.Organization) { return { key: "orgId" as const, value: dto.orgId }; @@ -60,6 +65,17 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep dto.permission.orgId ); ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Role); + + const externalGroupMapping = await externalGroupOrgRoleMappingDAL.findOne({ + orgId: dto.permission.orgId, + roleId: dto.selector.id + }); + + if (externalGroupMapping) + throw new BadRequestError({ + message: + "Cannot delete role assigned to external group organization role mapping. Please re-assign external mapping and try again." + }); }; const onListRoleGuard: TRoleScopeFactory["onListRoleGuard"] = async (dto) => { diff --git a/backend/src/services/role/role-service.ts b/backend/src/services/role/role-service.ts index 41a612a05..6aaf6cf52 100644 --- a/backend/src/services/role/role-service.ts +++ b/backend/src/services/role/role-service.ts @@ -8,6 +8,7 @@ import { validateHandlebarTemplate } from "@app/lib/template/validate-handlebars import { UnpackedPermissionSchema, unpackPermissions } from "@app/server/routes/sanitizedSchema/permission"; import { ActorType } from "../auth/auth-type"; +import { TExternalGroupOrgRoleMappingDALFactory } from "../external-group-org-role-mapping/external-group-org-role-mapping-dal"; import { TIdentityDALFactory } from "../identity/identity-dal"; import { TProjectDALFactory } from "../project/project-dal"; import { TUserDALFactory } from "../user/user-dal"; @@ -31,6 +32,7 @@ type TRoleServiceFactoryDep = { userDAL: Pick; permissionService: Pick; projectDAL: Pick; + externalGroupOrgRoleMappingDAL: Pick; }; export type TRoleServiceFactory = ReturnType; @@ -40,10 +42,12 @@ export const roleServiceFactory = ({ permissionService, projectDAL, identityDAL, - userDAL + userDAL, + externalGroupOrgRoleMappingDAL }: TRoleServiceFactoryDep) => { const orgRoleFactory = newOrgRoleFactory({ - permissionService + permissionService, + externalGroupOrgRoleMappingDAL }); const projectRoleFactory = newProjectRoleFactory({ permissionService,