}
// all gitlab users have an external ID, so the other two authentication methods should never be used
if (provider.getKey().equals("gitlab")) {
- throw loginAlreadyUsedException(userIdentity, source);
+ throw failAuthenticationException(userIdentity, source);
+ } else if (provider.getKey().equals("github")) {
+ validateEmailToAvoidLoginRecycling(userIdentity, user, source);
}
- validateEmailToAvoidLoginRecycling(userIdentity, user, source);
- updateUserExternalId(dbSession, user, userIdentity);
return user;
}
- private void updateUserExternalId(DbSession dbSession, UserDto user, UserIdentity userIdentity) {
- String externalId = userIdentity.getProviderId();
- if (externalId != null) {
- user.setExternalId(externalId);
- dbClient.userDao().update(dbSession, user);
- }
- }
-
private static void validateEmailToAvoidLoginRecycling(UserIdentity userIdentity, UserDto user, AuthenticationEvent.Source source) {
String dbEmail = user.getEmail();
String externalEmail = userIdentity.getEmail();
if (!dbEmail.equals(externalEmail)) {
- LOGGER.warn("User with login '{}' tried to login with email '{}' which doesn't match the email on record '{}'",
- userIdentity.getProviderLogin(), externalEmail, dbEmail);
- throw loginAlreadyUsedException(userIdentity, source);
+ LOGGER.warn("User with login '{}' tried to login with email '{}' which doesn't match the email on record '{}'", userIdentity.getProviderLogin(), externalEmail, dbEmail);
+ throw failAuthenticationException(userIdentity, source);
}
}
- private static AuthenticationException loginAlreadyUsedException(UserIdentity userIdentity, AuthenticationEvent.Source source) {
- return authException(
- userIdentity,
- source,
- String.format("Login '%s' is already used", userIdentity.getProviderLogin()),
- String.format("You can't sign up because login '%s' is already used by an existing user.", userIdentity.getProviderLogin()));
+ private static AuthenticationException failAuthenticationException(UserIdentity userIdentity, AuthenticationEvent.Source source) {
+ String message = String.format("Failed to authenticate with login '%s'", userIdentity.getProviderLogin());
+ return authException(userIdentity, source, message, message);
}
private static AuthenticationException authException(UserIdentity userIdentity, AuthenticationEvent.Source source, String message, String publicMessage) {
.setEmail("john@email.com")
.build();
- private static final TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
+ private static final TestIdentityProvider GH_IDENTITY_PROVIDER = new TestIdentityProvider()
.setKey("github")
.setName("name of github")
.setEnabled(true)
public void authenticate_new_user_throws_AuthenticationException_when_email_already_exists_multiple_times() {
db.users().insertUser(u -> u.setEmail("john@email.com"));
db.users().insertUser(u -> u.setEmail("john@email.com"));
- Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
+ Source source = Source.realm(AuthenticationEvent.Method.FORM, GH_IDENTITY_PROVIDER.getName());
expectedException.expect(authenticationException().from(source)
.withLogin(USER_IDENTITY.getProviderLogin())
@Test
public void authenticate_existing_user_doesnt_change_group_membership() {
- UserDto user = db.users().insertUser(u -> u.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ UserDto user = db.users().insertUser(u -> u.setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
GroupDto group1 = db.users().insertGroup("group1");
db.users().insertMember(group1, user);
db.users().insertMember(defaultGroup, user);
.setEmail("Old email")
.setExternalId(USER_IDENTITY.getProviderId())
.setExternalLogin("old identity")
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
.setEmail(USER_IDENTITY.getEmail())
.setExternalId("Old id")
.setExternalLogin(USER_IDENTITY.getProviderLogin())
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
.setEmail(USER_IDENTITY.getEmail())
.setExternalId(USER_IDENTITY.getProviderId())
.setExternalLogin("old identity")
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
.extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
UserDto::isActive)
.containsExactly("old login", USER_IDENTITY.getName(), USER_IDENTITY.getEmail(), USER_IDENTITY.getProviderId(), USER_IDENTITY.getProviderLogin(),
- IDENTITY_PROVIDER.getKey(), true);
+ GH_IDENTITY_PROVIDER.getKey(), true);
verify(auditPersister, never()).updateUserPassword(any(), any());
}
.setExternalId("Old id")
.setEmail("john@email.com")
.setExternalLogin("johndoo")
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration(UserIdentity.builder()
.setProviderId(null)
assertThatThrownBy(() -> underTest.register(registration))
.isInstanceOf(AuthenticationException.class)
- .hasMessage(String.format("Login '%s' is already used", USER_IDENTITY.getProviderLogin()));
+ .hasMessage(String.format("Failed to authenticate with login '%s'", USER_IDENTITY.getProviderLogin()));
}
@Test
- public void do_not_authenticate_and_update_existing_user_matching_external_login_if_emails_do_not_match() {
+ public void do_not_authenticate_and_update_existing_github_user_matching_external_login_if_emails_do_not_match() {
db.users().insertUser(u -> u
.setLogin("Old login")
.setName("Old name")
.setEmail("another-email@sonarsource.com")
.setExternalId("Old id")
.setExternalLogin(USER_IDENTITY.getProviderLogin())
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
assertThatThrownBy(() -> underTest.register(newUserRegistration()))
.isInstanceOf(AuthenticationException.class)
- .hasMessage(String.format("Login '%s' is already used", USER_IDENTITY.getProviderLogin()));
+ .hasMessage(String.format("Failed to authenticate with login '%s'", USER_IDENTITY.getProviderLogin()));
assertThat(logTester.logs()).contains(String.format("User with login '%s' tried to login with email '%s' which doesn't match the email on record '%s'",
USER_IDENTITY.getProviderLogin(), USER_IDENTITY.getEmail(), "another-email@sonarsource.com"));
}
+ @Test
+ public void authenticate_and_update_existing_user_matching_external_login_and_emails_mismatch() {
+ UserRegistration registration = UserRegistration.builder()
+ .setUserIdentity(USER_IDENTITY)
+ .setProvider(new TestIdentityProvider()
+ .setKey("other")
+ .setName("name of other")
+ .setEnabled(true))
+ .setSource(Source.local(BASIC))
+ .build();
+
+ UserDto user = db.users().insertUser(u -> u
+ .setLogin("Old login")
+ .setName("Old name")
+ .setEmail("another-email@sonarsource.com")
+ .setExternalId("Old id")
+ .setExternalLogin(USER_IDENTITY.getProviderLogin())
+ .setExternalIdentityProvider(registration.getProvider().getKey()));
+
+ underTest.register(registration);
+ assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
+ .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
+ UserDto::isActive)
+ .contains(user.getLogin(), "John", "john@email.com", "ABCD", "johndoo", "other", true);
+ }
+
@Test
public void authenticate_and_update_existing_user_matching_external_login_if_email_is_missing() {
db.users().insertUser(u -> u
.setExternalId("Old id")
.setEmail(null)
.setExternalLogin(USER_IDENTITY.getProviderLogin())
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
.setLogin("Old login")
.setExternalId(USER_IDENTITY.getProviderId())
.setExternalLogin("old identity")
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
.setEmail(USER_IDENTITY.getEmail())
.setExternalId("Old id")
.setExternalLogin(USER_IDENTITY.getProviderLogin())
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
underTest.register(newUserRegistration());
assertThat(userDto.getEmail()).isEqualTo(USER_IDENTITY.getEmail());
assertThat(userDto.getExternalId()).isEqualTo(USER_IDENTITY.getProviderId());
assertThat(userDto.getExternalLogin()).isEqualTo(USER_IDENTITY.getProviderLogin());
- assertThat(userDto.getExternalIdentityProvider()).isEqualTo(IDENTITY_PROVIDER.getKey());
+ assertThat(userDto.getExternalIdentityProvider()).isEqualTo(GH_IDENTITY_PROVIDER.getKey());
assertThat(userDto.isRoot()).isFalse();
}
.setEmail("john@email.com")
.build();
- Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
+ Source source = Source.realm(AuthenticationEvent.Method.FORM, GH_IDENTITY_PROVIDER.getName());
expectedException.expect(authenticationException().from(source)
.withLogin(userIdentity.getProviderLogin())
.andPublicMessage("This account is already associated with another authentication method."
@Test
public void authenticate_existing_user_succeeds_when_email_has_not_changed() {
UserDto currentUser = db.users().insertUser(u -> u.setEmail("john@email.com")
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey()));
UserIdentity userIdentity = UserIdentity.builder()
.setProviderId(currentUser.getExternalId())
.setProviderLogin(currentUser.getExternalLogin())
@Test
public void authenticate_existing_user_and_add_new_groups() {
UserDto user = db.users().insertUser(newUserDto()
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey())
.setExternalLogin(USER_IDENTITY.getProviderLogin())
.setEmail(USER_IDENTITY.getEmail())
.setActive(true)
@Test
public void authenticate_existing_user_and_remove_groups() {
UserDto user = db.users().insertUser(newUserDto()
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey())
.setExternalLogin(USER_IDENTITY.getProviderLogin())
.setEmail(USER_IDENTITY.getEmail())
.setActive(true)
@Test
public void authenticate_existing_user_and_remove_all_groups_expect_default() {
UserDto user = db.users().insertUser(newUserDto()
- .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
+ .setExternalIdentityProvider(GH_IDENTITY_PROVIDER.getKey())
.setExternalLogin(USER_IDENTITY.getProviderLogin()));
GroupDto group1 = db.users().insertGroup("group1");
GroupDto group2 = db.users().insertGroup("group2");
private static UserRegistration newUserRegistration(UserIdentity userIdentity, Source source) {
return UserRegistration.builder()
.setUserIdentity(userIdentity)
- .setProvider(IDENTITY_PROVIDER)
+ .setProvider(GH_IDENTITY_PROVIDER)
.setSource(source)
.build();
}