]> source.dussan.org Git - sonarqube.git/blob
6276d1ba27fb850f7e27502da4ab3e699fedcc52
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.authentication;
21
22 import java.util.Optional;
23 import java.util.Set;
24 import java.util.stream.Collectors;
25 import javax.annotation.Nullable;
26 import org.junit.Before;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.rules.ExpectedException;
30 import org.sonar.api.config.internal.MapSettings;
31 import org.sonar.api.impl.utils.AlwaysIncreasingSystem2;
32 import org.sonar.api.server.authentication.UserIdentity;
33 import org.sonar.api.utils.log.LogTester;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.user.GroupDto;
36 import org.sonar.db.user.UserDto;
37 import org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy;
38 import org.sonar.server.authentication.event.AuthenticationEvent;
39 import org.sonar.server.authentication.event.AuthenticationEvent.Source;
40 import org.sonar.server.authentication.event.AuthenticationException;
41 import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException;
42 import org.sonar.server.es.EsTester;
43 import org.sonar.server.user.NewUserNotifier;
44 import org.sonar.server.user.UserUpdater;
45 import org.sonar.server.user.index.UserIndexer;
46 import org.sonar.server.usergroups.DefaultGroupFinder;
47
48 import static java.util.Arrays.stream;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.assertj.core.api.Assertions.assertThatThrownBy;
51 import static org.mockito.Mockito.mock;
52 import static org.sonar.db.user.UserTesting.newUserDto;
53 import static org.sonar.process.ProcessProperties.Property.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS;
54 import static org.sonar.server.authentication.UserRegistration.ExistingEmailStrategy.FORBID;
55 import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC;
56 import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException;
57
58 public class UserRegistrarImplTest {
59   private static final String USER_LOGIN = "johndoo";
60
61   private static final UserIdentity USER_IDENTITY = UserIdentity.builder()
62     .setProviderId("ABCD")
63     .setProviderLogin(USER_LOGIN)
64     .setName("John")
65     .setEmail("john@email.com")
66     .build();
67
68   private static final TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
69     .setKey("github")
70     .setName("name of github")
71     .setEnabled(true)
72     .setAllowsUsersToSignUp(true);
73
74   private final MapSettings settings = new MapSettings().setProperty("sonar.internal.pbkdf2.iterations", "1");
75
76   @Rule
77   public ExpectedException expectedException = ExpectedException.none();
78   @Rule
79   public DbTester db = DbTester.create(new AlwaysIncreasingSystem2());
80   @Rule
81   public EsTester es = EsTester.create();
82   @Rule
83   public LogTester logTester = new LogTester();
84
85   private final UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
86   private final CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient(), settings.asConfig());
87   private final DefaultGroupFinder groupFinder = new DefaultGroupFinder(db.getDbClient());
88   private final UserUpdater userUpdater = new UserUpdater(mock(NewUserNotifier.class), db.getDbClient(), userIndexer, groupFinder, settings.asConfig(), localAuthentication);
89
90   private final UserRegistrarImpl underTest = new UserRegistrarImpl(db.getDbClient(), userUpdater, groupFinder);
91   private GroupDto defaultGroup;
92
93   @Before
94   public void setUp() {
95     defaultGroup = insertDefaultGroup();
96   }
97
98   @Test
99   public void authenticate_new_user() {
100     UserDto createdUser = underTest.register(newUserRegistration());
101
102     UserDto user = db.users().selectUserByLogin(createdUser.getLogin()).get();
103     assertThat(user).isNotNull();
104     assertThat(user.isActive()).isTrue();
105     assertThat(user.getName()).isEqualTo("John");
106     assertThat(user.getEmail()).isEqualTo("john@email.com");
107     assertThat(user.getExternalLogin()).isEqualTo(USER_LOGIN);
108     assertThat(user.getExternalIdentityProvider()).isEqualTo("github");
109     assertThat(user.getExternalId()).isEqualTo("ABCD");
110     assertThat(user.isRoot()).isFalse();
111     checkGroupMembership(user, defaultGroup);
112   }
113
114   @Test
115   public void authenticate_new_user_with_sq_identity() {
116     TestIdentityProvider sqIdentityProvider = new TestIdentityProvider()
117       .setKey("sonarqube")
118       .setName("sonarqube identity name")
119       .setEnabled(true)
120       .setAllowsUsersToSignUp(true);
121
122     UserDto createdUser = underTest.register(UserRegistration.builder()
123       .setUserIdentity(USER_IDENTITY)
124       .setProvider(sqIdentityProvider)
125       .setSource(Source.realm(BASIC, sqIdentityProvider.getName()))
126       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
127       .build());
128
129     UserDto user = db.users().selectUserByLogin(createdUser.getLogin()).get();
130     assertThat(user).isNotNull();
131     assertThat(user.isActive()).isTrue();
132     assertThat(user.getLogin()).isEqualTo(USER_LOGIN);
133     assertThat(user.getName()).isEqualTo("John");
134     assertThat(user.getEmail()).isEqualTo("john@email.com");
135     assertThat(user.getExternalLogin()).isEqualTo(USER_LOGIN);
136     assertThat(user.getExternalIdentityProvider()).isEqualTo("sonarqube");
137     assertThat(user.getExternalId()).isEqualTo("ABCD");
138     assertThat(user.isLocal()).isFalse();
139     assertThat(user.isRoot()).isFalse();
140     checkGroupMembership(user, defaultGroup);
141   }
142
143   @Test
144   public void authenticate_new_user_generates_login() {
145     underTest.register(newUserRegistration(UserIdentity.builder()
146       .setProviderId("ABCD")
147       .setProviderLogin(USER_LOGIN)
148       .setName("John Doe")
149       .setEmail("john@email.com")
150       .build()));
151
152     UserDto user = db.getDbClient().userDao().selectByEmail(db.getSession(), "john@email.com").get(0);
153     assertThat(user).isNotNull();
154     assertThat(user.isActive()).isTrue();
155     assertThat(user.getLogin()).isNotEqualTo("John Doe").startsWith("john-doe");
156     assertThat(user.getEmail()).isEqualTo("john@email.com");
157     assertThat(user.getExternalLogin()).isEqualTo(USER_LOGIN);
158     assertThat(user.getExternalIdentityProvider()).isEqualTo("github");
159     assertThat(user.getExternalId()).isEqualTo("ABCD");
160   }
161
162   @Test
163   public void authenticate_new_user_assigns_user_to_groups() {
164     GroupDto group1 = db.users().insertGroup("group1");
165     GroupDto group2 = db.users().insertGroup("group2");
166
167     UserDto loggedInUser = authenticate(USER_LOGIN, USER_IDENTITY.getEmail(), "group1", "group2", "group3");
168
169     Optional<UserDto> user = db.users().selectUserByLogin(loggedInUser.getLogin());
170     checkGroupMembership(user.get(), group1, group2, defaultGroup);
171   }
172
173   @Test
174   public void authenticate_new_user_sets_onboarded_flag_to_false_when_onboarding_setting_is_set_to_true() {
175     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS.getKey(), true);
176
177     UserDto user = underTest.register(newUserRegistration());
178
179     assertThat(db.users().selectUserByLogin(user.getLogin()).get().isOnboarded()).isFalse();
180   }
181
182   @Test
183   public void authenticate_new_user_sets_onboarded_flag_to_true_when_onboarding_setting_is_set_to_false() {
184     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS.getKey(), false);
185
186     UserDto user = underTest.register(newUserRegistration());
187
188     assertThat(db.users().selectUserByLogin(user.getLogin()).get().isOnboarded()).isTrue();
189   }
190
191   @Test
192   public void authenticate_new_user_sets_external_id_to_provider_login_when_id_is_null() {
193     UserIdentity newUser = UserIdentity.builder()
194       .setProviderId(null)
195       .setProviderLogin("johndoo")
196       .setName("JOhn")
197       .build();
198
199     UserDto user = underTest.register(newUserRegistration(newUser));
200
201     assertThat(db.users().selectUserByLogin(user.getLogin()).get())
202       .extracting(UserDto::getLogin, UserDto::getExternalId, UserDto::getExternalLogin)
203       .contains(user.getLogin(), "johndoo", "johndoo");
204   }
205
206   @Test
207   public void authenticate_new_user_with_gitlab_provider() {
208     UserRegistration registration = UserRegistration.builder()
209       .setUserIdentity(USER_IDENTITY)
210       .setProvider(new TestIdentityProvider()
211         .setKey("gitlab")
212         .setName("name of gitlab")
213         .setEnabled(true)
214         .setAllowsUsersToSignUp(true))
215       .setSource(Source.local(BASIC))
216       .setExistingEmailStrategy(FORBID)
217       .build();
218
219     UserDto newUser = underTest.register(registration);
220     assertThat(newUser)
221       .extracting(UserDto::getExternalIdentityProvider, UserDto::getExternalLogin)
222       .containsExactly("gitlab", USER_IDENTITY.getProviderLogin());
223   }
224
225   @Test
226   public void authenticate_new_user_update_existing_user_email_when_strategy_is_ALLOW() {
227     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
228     UserIdentity newUser = UserIdentity.builder()
229       .setProviderLogin("johndoo")
230       .setName(existingUser.getName())
231       .setEmail(existingUser.getEmail())
232       .build();
233
234     UserDto user = underTest.register(UserRegistration.builder()
235       .setUserIdentity(newUser)
236       .setProvider(IDENTITY_PROVIDER)
237       .setSource(Source.local(BASIC))
238       .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
239       .build());
240
241     UserDto newUserReloaded = db.users().selectUserByLogin(user.getLogin()).get();
242     assertThat(newUserReloaded.getEmail()).isEqualTo(existingUser.getEmail());
243     UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get();
244     assertThat(existingUserReloaded.getEmail()).isNull();
245   }
246
247   @Test
248   public void authenticate_new_user_throws_EmailAlreadyExistException_when_email_already_exists_and_strategy_is_WARN() {
249     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
250     UserIdentity newUser = UserIdentity.builder()
251       .setProviderLogin("johndoo")
252       .setName(existingUser.getName())
253       .setEmail(existingUser.getEmail())
254       .build();
255
256     expectedException.expect(EmailAlreadyExistsRedirectionException.class);
257
258     underTest.register(UserRegistration.builder()
259       .setUserIdentity(newUser)
260       .setProvider(IDENTITY_PROVIDER)
261       .setSource(Source.local(BASIC))
262       .setExistingEmailStrategy(ExistingEmailStrategy.WARN)
263       .build());
264   }
265
266   @Test
267   public void authenticate_new_user_throws_AuthenticationException_when_when_email_already_exists_and_strategy_is_FORBID() {
268     db.users().insertUser(u -> u.setEmail("john@email.com"));
269     Source source = Source.local(BASIC);
270
271     expectedException.expect(authenticationException().from(source)
272       .withLogin(USER_IDENTITY.getProviderLogin())
273       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
274         "This means that you probably already registered with another account."));
275     expectedException.expectMessage("Email 'john@email.com' is already used");
276
277     underTest.register(newUserRegistration());
278   }
279
280   @Test
281   public void authenticate_new_user_throws_AuthenticationException_when_email_already_exists_multiple_times() {
282     db.users().insertUser(u -> u.setEmail("john@email.com"));
283     db.users().insertUser(u -> u.setEmail("john@email.com"));
284     Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
285
286     expectedException.expect(authenticationException().from(source)
287       .withLogin(USER_IDENTITY.getProviderLogin())
288       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
289         "This means that you probably already registered with another account."));
290     expectedException.expectMessage("Email 'john@email.com' is already used");
291
292     underTest.register(newUserRegistration(source));
293   }
294
295   @Test
296   public void authenticate_new_user_fails_when_allow_users_to_signup_is_false() {
297     TestIdentityProvider identityProvider = new TestIdentityProvider()
298       .setKey("github")
299       .setName("Github")
300       .setEnabled(true)
301       .setAllowsUsersToSignUp(false);
302     Source source = Source.realm(AuthenticationEvent.Method.FORM, identityProvider.getName());
303
304     expectedException.expect(authenticationException().from(source).withLogin(USER_IDENTITY.getProviderLogin()).andPublicMessage("'github' users are not allowed to sign up"));
305     expectedException.expectMessage("User signup disabled for provider 'github'");
306
307     underTest.register(UserRegistration.builder()
308       .setUserIdentity(USER_IDENTITY)
309       .setProvider(identityProvider)
310       .setSource(source)
311       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
312       .build());
313   }
314
315   @Test
316   public void authenticate_existing_user_doesnt_change_group_membership() {
317     UserDto user = db.users().insertUser(u -> u.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
318     GroupDto group1 = db.users().insertGroup("group1");
319     db.users().insertMember(group1, user);
320     db.users().insertMember(defaultGroup, user);
321
322     authenticate(user.getExternalLogin(), user.getEmail(), "group1");
323
324     checkGroupMembership(user, group1, defaultGroup);
325   }
326
327   @Test
328   public void authenticate_and_update_existing_user_matching_external_id() {
329     UserDto user = db.users().insertUser(u -> u
330       .setLogin("Old login")
331       .setName("Old name")
332       .setEmail("Old email")
333       .setExternalId(USER_IDENTITY.getProviderId())
334       .setExternalLogin("old identity")
335       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
336
337     underTest.register(newUserRegistration());
338
339     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
340       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
341         UserDto::isActive)
342       .contains(USER_LOGIN, "John", "john@email.com", "ABCD", "johndoo", "github", true);
343   }
344
345   @Test
346   public void authenticate_and_update_existing_user_matching_external_login_and_email() {
347     UserDto user = db.users().insertUser(u -> u
348       .setLogin("Old login")
349       .setName("Old name")
350       .setEmail(USER_IDENTITY.getEmail())
351       .setExternalId("Old id")
352       .setExternalLogin(USER_IDENTITY.getProviderLogin())
353       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
354
355     underTest.register(newUserRegistration());
356
357     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
358       .extracting(UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
359         UserDto::isActive)
360       .contains("John", "john@email.com", "ABCD", "johndoo", "github", true);
361   }
362
363   @Test
364   public void authenticate_existing_user_should_not_update_login() {
365     UserDto user = db.users().insertUser(u -> u
366       .setLogin("old login")
367       .setName(USER_IDENTITY.getName())
368       .setEmail(USER_IDENTITY.getEmail())
369       .setExternalId(USER_IDENTITY.getProviderId())
370       .setExternalLogin("old identity")
371       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
372
373     underTest.register(newUserRegistration());
374
375     // no new user should be created
376     assertThat(db.countRowsOfTable(db.getSession(), "users")).isEqualTo(1);
377     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
378       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
379         UserDto::isActive)
380       .containsExactly("old login", USER_IDENTITY.getName(), USER_IDENTITY.getEmail(), USER_IDENTITY.getProviderId(), USER_IDENTITY.getProviderLogin(),
381         IDENTITY_PROVIDER.getKey(), true);
382   }
383
384   @Test
385   public void authenticate_existing_user_matching_external_login_and_email_when_external_id_is_null() {
386     UserDto user = db.users().insertUser(u -> u
387       .setName("Old name")
388       .setExternalId("Old id")
389       .setEmail("john@email.com")
390       .setExternalLogin("johndoo")
391       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
392
393     underTest.register(newUserRegistration(UserIdentity.builder()
394       .setProviderId(null)
395       .setProviderLogin("johndoo")
396       .setName("John")
397       .setEmail("john@email.com")
398       .build()));
399
400     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
401       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
402         UserDto::isActive)
403       .contains(user.getLogin(), "John", "john@email.com", "johndoo", "johndoo", "github", true);
404   }
405
406   @Test
407   public void do_not_authenticate_gitlab_user_matching_external_login() {
408     db.users().insertUser(u -> u
409       .setLogin("Old login")
410       .setName("Old name")
411       .setEmail(USER_IDENTITY.getEmail())
412       .setExternalId("Old id")
413       .setExternalLogin(USER_IDENTITY.getProviderLogin())
414       .setExternalIdentityProvider("gitlab"));
415
416     UserRegistration registration = UserRegistration.builder()
417       .setUserIdentity(USER_IDENTITY)
418       .setProvider(new TestIdentityProvider()
419         .setKey("gitlab")
420         .setName("name of gitlab")
421         .setEnabled(true))
422       .setSource(Source.local(BASIC))
423       .setExistingEmailStrategy(FORBID)
424       .build();
425
426     assertThatThrownBy(() -> underTest.register(registration))
427       .isInstanceOf(AuthenticationException.class)
428       .hasMessage(String.format("Login '%s' is already used", USER_IDENTITY.getProviderLogin()));
429   }
430
431   @Test
432   public void do_not_authenticate_and_update_existing_user_matching_external_login_if_emails_do_not_match() {
433     db.users().insertUser(u -> u
434       .setLogin("Old login")
435       .setName("Old name")
436       .setEmail("another-email@sonarsource.com")
437       .setExternalId("Old id")
438       .setExternalLogin(USER_IDENTITY.getProviderLogin())
439       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
440
441     assertThatThrownBy(() -> underTest.register(newUserRegistration()))
442       .isInstanceOf(AuthenticationException.class)
443       .hasMessage(String.format("Login '%s' is already used", USER_IDENTITY.getProviderLogin()));
444
445     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'",
446       USER_IDENTITY.getProviderLogin(), USER_IDENTITY.getEmail(), "another-email@sonarsource.com"));
447   }
448
449   @Test
450   public void do_not_authenticate_and_update_existing_user_matching_external_login_if_email_is_missing() {
451     db.users().insertUser(u -> u
452       .setLogin("Old login")
453       .setName("Old name")
454       .setExternalId("Old id")
455       .setEmail(null)
456       .setExternalLogin(USER_IDENTITY.getProviderLogin())
457       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
458
459     assertThatThrownBy(() -> underTest.register(newUserRegistration()))
460       .isInstanceOf(AuthenticationException.class)
461       .hasMessage(String.format("Login '%s' is already used", USER_IDENTITY.getProviderLogin()));
462
463     assertThat(logTester.logs()).contains(String.format("User with login '%s' tried to login with email '%s' but we don't have a email on record",
464       USER_IDENTITY.getProviderLogin(), USER_IDENTITY.getEmail()));
465   }
466
467   @Test
468   public void do_not_authenticate_and_update_existing_user_matching_external_id_if_external_provider_does_not_match() {
469     db.users().insertUser(u -> u
470       .setLogin("Old login")
471       .setName("Old name")
472       .setExternalId(USER_IDENTITY.getProviderId())
473       .setEmail(null)
474       .setExternalLogin(USER_IDENTITY.getProviderLogin())
475       .setExternalIdentityProvider("Old provider"));
476
477     underTest.register(newUserRegistration());
478     assertThat(db.countRowsOfTable("users")).isEqualTo(2);
479   }
480
481   @Test
482   public void authenticate_existing_user_should_update_login() {
483     UserDto user = db.users().insertUser(u -> u
484       .setLogin("Old login")
485       .setExternalId(USER_IDENTITY.getProviderId())
486       .setExternalLogin("old identity")
487       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
488
489     underTest.register(newUserRegistration());
490
491     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
492       .extracting(UserDto::getLogin, UserDto::getExternalLogin)
493       .contains(USER_LOGIN, USER_IDENTITY.getProviderLogin());
494   }
495
496   @Test
497   public void authenticate_existing_disabled_user_should_reactivate_it() {
498     db.users().insertUser(u -> u
499       .setLogin(USER_LOGIN)
500       .setActive(false)
501       .setName("Old name")
502       .setEmail(USER_IDENTITY.getEmail())
503       .setExternalId("Old id")
504       .setExternalLogin(USER_IDENTITY.getProviderLogin())
505       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
506
507     underTest.register(newUserRegistration());
508
509     UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get();
510     assertThat(userDto.isActive()).isTrue();
511     assertThat(userDto.getName()).isEqualTo(USER_IDENTITY.getName());
512     assertThat(userDto.getEmail()).isEqualTo(USER_IDENTITY.getEmail());
513     assertThat(userDto.getExternalId()).isEqualTo(USER_IDENTITY.getProviderId());
514     assertThat(userDto.getExternalLogin()).isEqualTo(USER_IDENTITY.getProviderLogin());
515     assertThat(userDto.getExternalIdentityProvider()).isEqualTo(IDENTITY_PROVIDER.getKey());
516     assertThat(userDto.isRoot()).isFalse();
517   }
518
519   @Test
520   public void authenticate_existing_user_when_email_already_exists_and_strategy_is_ALLOW() {
521     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
522     UserDto currentUser = db.users().insertUser(u -> u.setExternalId("id").setExternalLogin("login").setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()).setEmail(null));
523
524     UserIdentity userIdentity = UserIdentity.builder()
525       .setProviderLogin(currentUser.getExternalLogin())
526       .setProviderId(currentUser.getExternalId())
527       .setName("John")
528       .setEmail("john@email.com")
529       .build();
530
531     currentUser = underTest.register(UserRegistration.builder()
532       .setUserIdentity(userIdentity)
533       .setProvider(IDENTITY_PROVIDER)
534       .setSource(Source.local(BASIC))
535       .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
536       .build());
537
538     UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get();
539     assertThat(existingUserReloaded.getEmail()).isNull();
540
541     UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get();
542     assertThat(currentUserReloaded.getEmail()).isEqualTo("john@email.com");
543
544   }
545
546   @Test
547   public void authenticating_existing_user_throws_EmailAlreadyExistException_when_email_already_exists_and_strategy_is_WARN() {
548     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
549     UserDto currentUser = db.users().insertUser(u -> u.setEmail(null));
550     UserIdentity userIdentity = UserIdentity.builder()
551       .setProviderLogin("johndoo")
552       .setName("John")
553       .setEmail("john@email.com")
554       .build();
555
556     expectedException.expect(EmailAlreadyExistsRedirectionException.class);
557
558     underTest.register(UserRegistration.builder()
559       .setUserIdentity(userIdentity)
560       .setProvider(IDENTITY_PROVIDER)
561       .setSource(Source.local(BASIC))
562       .setExistingEmailStrategy(ExistingEmailStrategy.WARN)
563       .build());
564   }
565
566   @Test
567   public void authenticating_existing_user_throws_AuthenticationException_when_email_already_exists_and_strategy_is_FORBID() {
568     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
569     UserDto currentUser = db.users().insertUser(u -> u.setEmail(null));
570     UserIdentity userIdentity = UserIdentity.builder()
571       .setProviderLogin("johndoo")
572       .setName("John")
573       .setEmail("john@email.com")
574       .build();
575
576     Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
577     expectedException.expect(authenticationException().from(source)
578       .withLogin(userIdentity.getProviderLogin())
579       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
580         "This means that you probably already registered with another account."));
581     expectedException.expectMessage("Email 'john@email.com' is already used");
582
583     underTest.register(newUserRegistration(userIdentity, source));
584   }
585
586   @Test
587   public void authenticate_existing_user_succeeds_when_email_has_not_changed_and_strategy_is_FORBID() {
588     UserDto currentUser = db.users().insertUser(u -> u.setEmail("john@email.com")
589       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
590     UserIdentity userIdentity = UserIdentity.builder()
591       .setProviderId(currentUser.getExternalId())
592       .setProviderLogin(currentUser.getExternalLogin())
593       .setName("John")
594       .setEmail("john@email.com")
595       .build();
596
597     underTest.register(newUserRegistration(userIdentity));
598
599     UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get();
600     assertThat(currentUserReloaded.getEmail()).isEqualTo("john@email.com");
601   }
602
603   @Test
604   public void authenticate_existing_user_and_add_new_groups() {
605     UserDto user = db.users().insertUser(newUserDto()
606       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
607       .setExternalLogin(USER_IDENTITY.getProviderLogin())
608       .setEmail(USER_IDENTITY.getEmail())
609       .setActive(true)
610       .setName("John"));
611     GroupDto group1 = db.users().insertGroup("group1");
612     GroupDto group2 = db.users().insertGroup("group2");
613
614     authenticate(USER_IDENTITY.getProviderLogin(), USER_IDENTITY.getEmail(), "group1", "group2", "group3");
615
616     checkGroupMembership(user, group1, group2);
617   }
618
619   @Test
620   public void authenticate_existing_user_and_remove_groups() {
621     UserDto user = db.users().insertUser(newUserDto()
622       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
623       .setExternalLogin(USER_IDENTITY.getProviderLogin())
624       .setEmail(USER_IDENTITY.getEmail())
625       .setActive(true)
626       .setName("John"));
627     GroupDto group1 = db.users().insertGroup("group1");
628     GroupDto group2 = db.users().insertGroup("group2");
629     db.users().insertMember(group1, user);
630     db.users().insertMember(group2, user);
631
632     authenticate(USER_IDENTITY.getProviderLogin(), USER_IDENTITY.getEmail(), "group1");
633
634     checkGroupMembership(user, group1);
635   }
636
637   @Test
638   public void authenticate_existing_user_and_remove_all_groups_expect_default() {
639     UserDto user = db.users().insertUser(newUserDto()
640       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
641       .setExternalLogin(USER_IDENTITY.getProviderLogin()));
642     GroupDto group1 = db.users().insertGroup("group1");
643     GroupDto group2 = db.users().insertGroup("group2");
644     db.users().insertMember(group1, user);
645     db.users().insertMember(group2, user);
646     db.users().insertMember(defaultGroup, user);
647
648     authenticate(user.getExternalLogin(), user.getEmail());
649
650     checkGroupMembership(user, defaultGroup);
651   }
652
653   private static UserRegistration newUserRegistration(UserIdentity userIdentity) {
654     return newUserRegistration(userIdentity, Source.local(BASIC));
655   }
656
657   private static UserRegistration newUserRegistration(UserIdentity userIdentity, Source source) {
658     return UserRegistration.builder()
659       .setUserIdentity(userIdentity)
660       .setProvider(IDENTITY_PROVIDER)
661       .setSource(source)
662       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
663       .build();
664   }
665
666   private static UserRegistration newUserRegistration(Source source) {
667     return newUserRegistration(USER_IDENTITY, source);
668   }
669
670   private static UserRegistration newUserRegistration() {
671     return newUserRegistration(USER_IDENTITY, Source.local(BASIC));
672   }
673
674   private UserDto authenticate(String providerLogin, @Nullable String email, String... groups) {
675     return underTest.register(newUserRegistration(UserIdentity.builder()
676       .setProviderLogin(providerLogin)
677       .setName("John")
678       .setEmail(email)
679       .setGroups(Set.of(groups))
680       .build()));
681   }
682
683   private void checkGroupMembership(UserDto user, GroupDto... expectedGroups) {
684     assertThat(db.users().selectGroupUuidsOfUser(user)).containsOnly(stream(expectedGroups).map(GroupDto::getUuid).collect(Collectors.toList()).toArray(new String[] {}));
685   }
686
687   private GroupDto insertDefaultGroup() {
688     return db.users().insertDefaultGroup();
689   }
690
691 }