diff --git a/packages/cli/src/controllers/users.controller.ts b/packages/cli/src/controllers/users.controller.ts index 391c98c70fff8..19f929dd5ca94 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 b58f88795de34..f24e9aaab0359 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;