1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-24 17:51:14 +02:00

fix: users managed by SCIM should not get their name updated

This commit is contained in:
Gastón Fournier 2025-09-22 17:16:23 +02:00
parent 7cec4d6923
commit e74ac423c6
No known key found for this signature in database
GPG Key ID: AF45428626E17A8E
2 changed files with 176 additions and 119 deletions

View File

@ -506,9 +506,30 @@ export class UserService {
try { try {
user = await this.store.getByQuery({ email }); user = await this.store.getByQuery({ email });
// Update user if autCreate is enabled. // Update user if not managed by scim
if (name && user.name !== name) { if (name && user.name !== name && !user.scimId) {
user = await this.store.update(user.id, { name, email }); const currentRole = await this.accessService.getRootRoleForUser(
user.id,
);
const updatedUser = await this.store.update(user.id, {
name,
email,
});
await this.eventService.storeEvent(
new UserUpdatedEvent({
auditUser: SYSTEM_USER_AUDIT,
preUser: {
...user,
rootRole: currentRole.id,
},
postUser: {
...updatedUser,
rootRole: currentRole.id,
},
}),
);
user = { ...user, ...updatedUser };
} }
} catch (e) { } catch (e) {
// User does not exists. Create if 'autoCreate' is enabled // User does not exists. Create if 'autoCreate' is enabled

View File

@ -435,141 +435,177 @@ test('updating a user without an email should not strip the email', async () =>
expect(updatedUser.email).toBe(email); expect(updatedUser.email).toBe(email);
}); });
test('should login and create user via SSO', async () => { describe('loginUserSSO', () => {
const recordedEvents: Array<{ loginOrder: number }> = []; test('should login and create user via SSO', async () => {
eventBus.on(USER_LOGIN, (data) => { const recordedEvents: Array<{ loginOrder: number }> = [];
recordedEvents.push(data); eventBus.on(USER_LOGIN, (data) => {
}); recordedEvents.push(data);
const email = 'some@test.com'; });
const user = await userService.loginUserSSO({ const email = 'some@test.com';
email, const user = await userService.loginUserSSO({
rootRole: RoleName.VIEWER, email,
name: 'some', rootRole: RoleName.VIEWER,
autoCreate: true,
});
const userWithRole = await userService.getUser(user.id);
expect(user.email).toBe(email);
expect(user.name).toBe('some');
expect(userWithRole.name).toBe('some');
expect(userWithRole.rootRole).toBe(viewerRole.id);
expect(recordedEvents).toEqual([{ loginOrder: 0 }]);
});
test('should throw if rootRole is wrong via SSO', async () => {
expect.assertions(1);
await expect(
userService.loginUserSSO({
email: 'some@test.com',
rootRole: RoleName.MEMBER,
name: 'some', name: 'some',
autoCreate: true, autoCreate: true,
}), });
).rejects.errorWithMessage(
new BadDataError('Could not find rootRole=Member'),
);
});
test('should update user name when signing in via SSO', async () => { const userWithRole = await userService.getUser(user.id);
const email = 'some@test.com'; expect(user.email).toBe(email);
const originalUser = await userService.createUser( expect(user.name).toBe('some');
{ expect(userWithRole.name).toBe('some');
email, expect(userWithRole.rootRole).toBe(viewerRole.id);
rootRole: RoleName.VIEWER, expect(recordedEvents).toEqual([{ loginOrder: 0 }]);
name: 'some',
},
TEST_AUDIT_USER,
);
await userService.loginUserSSO({
email,
rootRole: RoleName.ADMIN,
name: 'New name!',
autoCreate: true,
}); });
const actualUser = await userService.getUser(originalUser.id); test('should throw if rootRole is wrong via SSO', async () => {
expect.assertions(1);
expect(actualUser.email).toBe(email); await expect(
expect(actualUser.name).toBe('New name!'); userService.loginUserSSO({
expect(actualUser.rootRole).toBe(viewerRole.id); email: 'some@test.com',
}); rootRole: RoleName.MEMBER,
name: 'some',
test('should update name if it is different via SSO', async () => { autoCreate: true,
const email = 'some@test.com'; }),
const originalUser = await userService.createUser( ).rejects.errorWithMessage(
{ new BadDataError('Could not find rootRole=Member'),
email, );
rootRole: RoleName.VIEWER,
name: 'some',
},
TEST_AUDIT_USER,
);
await userService.loginUserSSO({
email,
rootRole: RoleName.ADMIN,
name: 'New name!',
autoCreate: false,
}); });
const actualUser = await userService.getUser(originalUser.id); test('should update user name when signing in via SSO', async () => {
const email = 'some@test.com';
const originalUser = await userService.createUser(
{
email,
rootRole: RoleName.VIEWER,
name: 'some',
},
TEST_AUDIT_USER,
);
expect(actualUser.email).toBe(email); await userService.loginUserSSO({
expect(actualUser.name).toBe('New name!'); email,
expect(actualUser.rootRole).toBe(viewerRole.id); rootRole: RoleName.ADMIN,
}); name: 'New name!',
autoCreate: true,
});
test('should throw if autoCreate is false via SSO', async () => { const actualUser = await userService.getUser(originalUser.id);
expect.assertions(1);
await expect( expect(actualUser.email).toBe(email);
userService.loginUserSSO({ expect(actualUser.name).toBe('New name!');
email: 'some@test.com', expect(actualUser.rootRole).toBe(viewerRole.id);
rootRole: RoleName.MEMBER, const { events } = await eventService.getEvents();
name: 'some', const updateEvent = events.find(
(e) => e.data.id === originalUser.id && e.data.name === 'New name!',
);
expect(updateEvent).toBeDefined();
});
test('should update name if it is different via SSO', async () => {
const email = 'some@test.com';
const originalUser = await userService.createUser(
{
email,
rootRole: RoleName.VIEWER,
name: 'some',
},
TEST_AUDIT_USER,
);
await userService.loginUserSSO({
email,
rootRole: RoleName.ADMIN,
name: 'New name!',
autoCreate: false, autoCreate: false,
}), });
).rejects.errorWithMessage(new NotFoundError('No user found'));
});
test('should support a root role id when logging in and creating user via SSO', async () => { const actualUser = await userService.getUser(originalUser.id);
const name = 'root-role-id';
const email = `${name}@test.com`; expect(actualUser.email).toBe(email);
const user = await userService.loginUserSSO({ expect(actualUser.name).toBe('New name!');
email, expect(actualUser.rootRole).toBe(viewerRole.id);
rootRole: viewerRole.id,
name,
autoCreate: true,
}); });
const userWithRole = await userService.getUser(user.id); test('should throw if autoCreate is false via SSO', async () => {
expect(user.email).toBe(email); expect.assertions(1);
expect(user.name).toBe(name);
expect(userWithRole.name).toBe(name);
expect(userWithRole.rootRole).toBe(viewerRole.id);
});
test('should support a custom root role id when logging in and creating user via SSO', async () => { await expect(
const name = 'custom-root-role-id'; userService.loginUserSSO({
const email = `${name}@test.com`; email: 'some@test.com',
const user = await userService.loginUserSSO({ rootRole: RoleName.MEMBER,
email, name: 'some',
rootRole: customRole.id, autoCreate: false,
name, }),
autoCreate: true, ).rejects.errorWithMessage(new NotFoundError('No user found'));
}); });
const userWithRole = await userService.getUser(user.id); test('should support a root role id when logging in and creating user via SSO', async () => {
expect(user.email).toBe(email); const name = 'root-role-id';
expect(user.name).toBe(name); const email = `${name}@test.com`;
expect(userWithRole.name).toBe(name); const user = await userService.loginUserSSO({
expect(userWithRole.rootRole).toBe(customRole.id); email,
rootRole: viewerRole.id,
name,
autoCreate: true,
});
const permissions = await accessService.getPermissionsForUser(user); const userWithRole = await userService.getUser(user.id);
expect(permissions).toHaveLength(1); expect(user.email).toBe(email);
expect(permissions[0].permission).toBe(CREATE_ADDON); expect(user.name).toBe(name);
expect(userWithRole.name).toBe(name);
expect(userWithRole.rootRole).toBe(viewerRole.id);
});
test('should support a custom root role id when logging in and creating user via SSO', async () => {
const name = 'custom-root-role-id';
const email = `${name}@test.com`;
const user = await userService.loginUserSSO({
email,
rootRole: customRole.id,
name,
autoCreate: true,
});
const userWithRole = await userService.getUser(user.id);
expect(user.email).toBe(email);
expect(user.name).toBe(name);
expect(userWithRole.name).toBe(name);
expect(userWithRole.rootRole).toBe(customRole.id);
const permissions = await accessService.getPermissionsForUser(user);
expect(permissions).toHaveLength(1);
expect(permissions[0].permission).toBe(CREATE_ADDON);
});
test(`should not update the username if managed by SCIM`, async () => {
const email = 'test-1@getunleash.io';
const originalName = 'Original Name';
const name = 'Updated Name';
const createdUser = await userStore.insert({
name: originalName,
username: 'random-1234',
email,
});
await db
.rawDatabase('users')
.update({
scim_id: '123',
})
.where({ id: createdUser.id });
const user = await userService.loginUserSSO({
email,
autoCreate: true,
name,
});
expect(user.name).toBe(originalName);
// Fetch the user directly from the store to verify
const storedUser = await userStore.get(user.id);
expect(storedUser!.name).toBe(originalName);
});
}); });
describe('Should not be able to use any of previous 5 passwords', () => { describe('Should not be able to use any of previous 5 passwords', () => {