chore(core): Adapt OIDC to match SAML behavior for signup (#17234)

This commit is contained in:
Andreas Fitzek
2025-07-11 18:06:42 +02:00
committed by GitHub
parent 6a2edf83ab
commit 7195b3bd97
2 changed files with 21 additions and 9 deletions

View File

@@ -104,10 +104,6 @@ export class OidcService {
throw new BadRequestError('An email is required'); throw new BadRequestError('An email is required');
} }
if (!userInfo.email_verified) {
throw new BadRequestError('Email needs to be verified');
}
const openidUser = await this.authIdentityRepository.findOne({ const openidUser = await this.authIdentityRepository.findOne({
where: { providerId: claims.sub, providerType: 'oidc' }, where: { providerId: claims.sub, providerType: 'oidc' },
relations: ['user'], relations: ['user'],
@@ -120,7 +116,19 @@ export class OidcService {
const foundUser = await this.userRepository.findOneBy({ email: userInfo.email }); const foundUser = await this.userRepository.findOneBy({ email: userInfo.email });
if (foundUser) { if (foundUser) {
throw new BadRequestError('User already exist with that email.'); this.logger.debug(
`OIDC login: User with email ${userInfo.email} already exists, linking OIDC identity.`,
);
// If the user already exists, we just add the OIDC identity to the user
const id = this.authIdentityRepository.create({
providerId: claims.sub,
providerType: 'oidc',
userId: foundUser.id,
});
await this.authIdentityRepository.save(id);
return foundUser;
} }
return await this.userRepository.manager.transaction(async (trx) => { return await this.userRepository.manager.transaction(async (trx) => {

View File

@@ -248,7 +248,7 @@ describe('OIDC service', () => {
expect(user.id).toEqual(createdUser.id); expect(user.id).toEqual(createdUser.id);
}); });
it('should throw `BadRequestError` if user already exists out of OIDC system', async () => { it('should sign up the user if user already exists out of OIDC system', async () => {
const callbackUrl = new URL( const callbackUrl = new URL(
'http://localhost:5678/rest/sso/oidc/callback?code=valid-code&state=valid-state', 'http://localhost:5678/rest/sso/oidc/callback?code=valid-code&state=valid-state',
); );
@@ -279,10 +279,12 @@ describe('OIDC service', () => {
email: 'user1@example.com', email: 'user1@example.com',
}); });
await expect(oidcService.loginUser(callbackUrl)).rejects.toThrowError(BadRequestError); const user = await oidcService.loginUser(callbackUrl);
expect(user).toBeDefined();
expect(user.email).toEqual('user1@example.com');
}); });
it('should throw `BadRequestError` if OIDC Idp does not have email verified', async () => { it('should sign in user if OIDC Idp does not have email verified', async () => {
const callbackUrl = new URL( const callbackUrl = new URL(
'http://localhost:5678/rest/sso/oidc/callback?code=valid-code&state=valid-state', 'http://localhost:5678/rest/sso/oidc/callback?code=valid-code&state=valid-state',
); );
@@ -313,7 +315,9 @@ describe('OIDC service', () => {
email: 'user3@example.com', email: 'user3@example.com',
}); });
await expect(oidcService.loginUser(callbackUrl)).rejects.toThrowError(BadRequestError); const user = await oidcService.loginUser(callbackUrl);
expect(user).toBeDefined();
expect(user.email).toEqual('user3@example.com');
}); });
it('should throw `BadRequestError` if OIDC Idp does not provide an email', async () => { it('should throw `BadRequestError` if OIDC Idp does not provide an email', async () => {