From 88b9a4070b7df943c3ba22047c0656a5d0a2111c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=95=E0=A4=BE=E0=A4=B0=E0=A4=A4=E0=A5=8B=E0=A4=AB?= =?UTF-8?q?=E0=A5=8D=E0=A4=AB=E0=A5=87=E0=A4=B2=E0=A4=B8=E0=A5=8D=E0=A4=95?= =?UTF-8?q?=E0=A5=8D=E0=A4=B0=E0=A4=BF=E0=A4=AA=E0=A5=8D=E0=A4=9F=E2=84=A2?= Date: Wed, 22 May 2024 16:13:56 +0200 Subject: [PATCH] fix(core): Do not allow admins to generate password-reset links for instance owner (#9488) --- .../cli/src/controllers/users.controller.ts | 4 ++ .../cli/test/integration/users.api.test.ts | 39 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/controllers/users.controller.ts b/packages/cli/src/controllers/users.controller.ts index 391c98c70f..19f929dd5c 100644 --- a/packages/cli/src/controllers/users.controller.ts +++ b/packages/cli/src/controllers/users.controller.ts @@ -115,6 +115,10 @@ export class UsersController { throw new NotFoundError('User not found'); } + if (req.user.role === 'global:admin' && user.role === 'global:owner') { + throw new ForbiddenError('Admin cannot reset password of global owner'); + } + const link = this.authService.generatePasswordResetUrl(user); return { link }; } diff --git a/packages/cli/test/integration/users.api.test.ts b/packages/cli/test/integration/users.api.test.ts index b58f88795d..f24e9aaab0 100644 --- a/packages/cli/test/integration/users.api.test.ts +++ b/packages/cli/test/integration/users.api.test.ts @@ -35,12 +35,6 @@ const testServer = utils.setupTestServer({ enabledFeatures: ['feat:advancedPermissions'], }); -let projectRepository: ProjectRepository; - -beforeAll(() => { - projectRepository = Container.get(ProjectRepository); -}); - describe('GET /users', () => { let owner: User; let member: User; @@ -243,6 +237,39 @@ describe('GET /users', () => { }); }); +describe('GET /users/:id/password-reset-link', () => { + let owner: User; + let admin: User; + let member: User; + + beforeAll(async () => { + await testDb.truncate(['User']); + + [owner, admin, member] = await Promise.all([createOwner(), createAdmin(), createMember()]); + }); + + it('should allow owners to generate password reset links for admins and members', async () => { + const ownerAgent = testServer.authAgentFor(owner); + await ownerAgent.get(`/users/${owner.id}/password-reset-link`).expect(200); + await ownerAgent.get(`/users/${admin.id}/password-reset-link`).expect(200); + await ownerAgent.get(`/users/${member.id}/password-reset-link`).expect(200); + }); + + it('should allow admins to generate password reset links for admins and members, but not owners', async () => { + const adminAgent = testServer.authAgentFor(admin); + await adminAgent.get(`/users/${owner.id}/password-reset-link`).expect(403); + await adminAgent.get(`/users/${admin.id}/password-reset-link`).expect(200); + await adminAgent.get(`/users/${member.id}/password-reset-link`).expect(200); + }); + + it('should not allow members to generate password reset links for anyone', async () => { + const memberAgent = testServer.authAgentFor(member); + await memberAgent.get(`/users/${owner.id}/password-reset-link`).expect(403); + await memberAgent.get(`/users/${admin.id}/password-reset-link`).expect(403); + await memberAgent.get(`/users/${member.id}/password-reset-link`).expect(403); + }); +}); + describe('DELETE /users/:id', () => { let owner: User; let ownerAgent: SuperAgentTest;