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