]> source.dussan.org Git - sonarqube.git/blob
d054ddb9492456f187b02897bab3b530214af238
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2018 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.Rule;
25 import org.junit.Test;
26 import org.junit.rules.ExpectedException;
27 import org.sonar.api.config.internal.MapSettings;
28 import org.sonar.api.resources.Qualifiers;
29 import org.sonar.api.resources.ResourceTypes;
30 import org.sonar.api.server.authentication.UserIdentity;
31 import org.sonar.api.utils.System2;
32 import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
33 import org.sonar.core.util.UuidFactoryFast;
34 import org.sonar.core.util.stream.MoreCollectors;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.component.ResourceTypesRule;
37 import org.sonar.db.organization.OrganizationDto;
38 import org.sonar.db.user.GroupDto;
39 import org.sonar.db.user.UserDto;
40 import org.sonar.server.authentication.UserIdentityAuthenticatorParameters.ExistingEmailStrategy;
41 import org.sonar.server.authentication.UserIdentityAuthenticatorParameters.UpdateLoginStrategy;
42 import org.sonar.server.authentication.event.AuthenticationEvent;
43 import org.sonar.server.authentication.event.AuthenticationEvent.Source;
44 import org.sonar.server.authentication.exception.EmailAlreadyExistsRedirectionException;
45 import org.sonar.server.authentication.exception.UpdateLoginRedirectionException;
46 import org.sonar.server.es.EsTester;
47 import org.sonar.server.organization.DefaultOrganizationProvider;
48 import org.sonar.server.organization.OrganizationUpdater;
49 import org.sonar.server.organization.OrganizationUpdaterImpl;
50 import org.sonar.server.organization.OrganizationValidationImpl;
51 import org.sonar.server.organization.TestDefaultOrganizationProvider;
52 import org.sonar.server.organization.TestOrganizationFlags;
53 import org.sonar.server.permission.PermissionService;
54 import org.sonar.server.permission.PermissionServiceImpl;
55 import org.sonar.server.user.NewUserNotifier;
56 import org.sonar.server.user.UserUpdater;
57 import org.sonar.server.user.index.UserIndexer;
58 import org.sonar.server.usergroups.DefaultGroupFinder;
59
60 import static com.google.common.collect.Sets.newHashSet;
61 import static java.util.Arrays.stream;
62 import static org.assertj.core.api.Assertions.assertThat;
63 import static org.mockito.Mockito.mock;
64 import static org.sonar.core.config.CorePropertyDefinitions.ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS;
65 import static org.sonar.db.user.UserTesting.newUserDto;
66 import static org.sonar.server.authentication.UserIdentityAuthenticatorParameters.ExistingEmailStrategy.FORBID;
67 import static org.sonar.server.authentication.event.AuthenticationEvent.Method.BASIC;
68 import static org.sonar.server.authentication.event.AuthenticationExceptionMatcher.authenticationException;
69
70 public class UserIdentityAuthenticatorImplTest {
71
72   private static String USER_LOGIN = "github-johndoo";
73
74   private static UserIdentity USER_IDENTITY = UserIdentity.builder()
75     .setProviderId("ABCD")
76     .setProviderLogin("johndoo")
77     .setLogin(USER_LOGIN)
78     .setName("John")
79     .setEmail("john@email.com")
80     .build();
81
82   private static TestIdentityProvider IDENTITY_PROVIDER = new TestIdentityProvider()
83     .setKey("github")
84     .setName("name of github")
85     .setEnabled(true)
86     .setAllowsUsersToSignUp(true);
87
88   private MapSettings settings = new MapSettings();
89
90   @Rule
91   public ExpectedException expectedException = ExpectedException.none();
92   @Rule
93   public DbTester db = DbTester.create(new AlwaysIncreasingSystem2());
94   @Rule
95   public EsTester es = EsTester.create();
96   private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
97   private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
98   private OrganizationUpdater organizationUpdater = mock(OrganizationUpdater.class);
99   private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
100   private CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient());
101   private UserUpdater userUpdater = new UserUpdater(
102     mock(NewUserNotifier.class),
103     db.getDbClient(),
104     userIndexer,
105     organizationFlags,
106     defaultOrganizationProvider,
107     organizationUpdater,
108     new DefaultGroupFinder(db.getDbClient()),
109     settings.asConfig(),
110     localAuthentication);
111
112   private ResourceTypes resourceTypes = new ResourceTypesRule().setRootQualifiers(Qualifiers.PROJECT);
113   private PermissionService permissionService = new PermissionServiceImpl(resourceTypes);
114
115   private UserIdentityAuthenticatorImpl underTest = new UserIdentityAuthenticatorImpl(db.getDbClient(), userUpdater, defaultOrganizationProvider, organizationFlags,
116     new OrganizationUpdaterImpl(db.getDbClient(), mock(System2.class), UuidFactoryFast.getInstance(),
117       new OrganizationValidationImpl(), settings.asConfig(), null, null, null, permissionService),
118     new DefaultGroupFinder(db.getDbClient()));
119
120   @Test
121   public void authenticate_new_user() {
122     organizationFlags.setEnabled(true);
123
124     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
125       .setUserIdentity(USER_IDENTITY)
126       .setProvider(IDENTITY_PROVIDER)
127       .setSource(Source.realm(BASIC, IDENTITY_PROVIDER.getName()))
128       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
129       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
130       .build());
131
132     UserDto user = db.users().selectUserByLogin(USER_LOGIN).get();
133     assertThat(user).isNotNull();
134     assertThat(user.isActive()).isTrue();
135     assertThat(user.getName()).isEqualTo("John");
136     assertThat(user.getEmail()).isEqualTo("john@email.com");
137     assertThat(user.getExternalLogin()).isEqualTo("johndoo");
138     assertThat(user.getExternalIdentityProvider()).isEqualTo("github");
139     assertThat(user.getExternalId()).isEqualTo("ABCD");
140     assertThat(user.isRoot()).isFalse();
141     checkGroupMembership(user);
142   }
143
144   @Test
145   public void authenticate_new_user_generate_login_when_no_login_provided() {
146     organizationFlags.setEnabled(true);
147
148     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
149       .setUserIdentity(UserIdentity.builder()
150         .setProviderId("ABCD")
151         .setProviderLogin("johndoo")
152         .setName("John Doe")
153         .setEmail("john@email.com")
154         .build())
155       .setProvider(IDENTITY_PROVIDER)
156       .setSource(Source.realm(BASIC, IDENTITY_PROVIDER.getName()))
157       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
158       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
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     organizationFlags.setEnabled(true);
174     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
175     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
176
177     authenticate(USER_LOGIN, "group1", "group2", "group3");
178
179     Optional<UserDto> user = db.users().selectUserByLogin(USER_LOGIN);
180     checkGroupMembership(user.get(), group1, group2);
181   }
182
183   @Test
184   public void authenticate_new_user_and_force_default_group_when_organizations_are_disabled() {
185     organizationFlags.setEnabled(false);
186     UserDto user = db.users().insertUser();
187     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
188     GroupDto defaultGroup = insertDefaultGroup();
189     db.users().insertMember(group1, user);
190     db.users().insertMember(defaultGroup, user);
191
192     authenticate(user.getLogin(), "group1");
193
194     checkGroupMembership(user, group1, defaultGroup);
195   }
196
197   @Test
198   public void does_not_force_default_group_when_authenticating_new_user_if_organizations_are_enabled() {
199     organizationFlags.setEnabled(true);
200     UserDto user = db.users().insertUser();
201     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
202     GroupDto defaultGroup = insertDefaultGroup();
203     db.users().insertMember(group1, user);
204     db.users().insertMember(defaultGroup, user);
205
206     authenticate(user.getLogin(), "group1");
207
208     checkGroupMembership(user, group1);
209   }
210
211   @Test
212   public void authenticate_new_user_sets_onboarded_flag_to_false_when_onboarding_setting_is_set_to_true() {
213     organizationFlags.setEnabled(true);
214     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, true);
215
216     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
217       .setUserIdentity(USER_IDENTITY)
218       .setProvider(IDENTITY_PROVIDER)
219       .setSource(Source.local(BASIC))
220       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
221       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
222       .build());
223
224     assertThat(db.users().selectUserByLogin(USER_LOGIN).get().isOnboarded()).isFalse();
225   }
226
227   @Test
228   public void authenticate_new_user_sets_onboarded_flag_to_true_when_onboarding_setting_is_set_to_false() {
229     organizationFlags.setEnabled(true);
230     settings.setProperty(ONBOARDING_TUTORIAL_SHOW_TO_NEW_USERS, false);
231
232     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
233       .setUserIdentity(USER_IDENTITY)
234       .setProvider(IDENTITY_PROVIDER)
235       .setSource(Source.local(BASIC))
236       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
237       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
238       .build());
239
240     assertThat(db.users().selectUserByLogin(USER_LOGIN).get().isOnboarded()).isTrue();
241   }
242
243   @Test
244   public void external_id_is_set_to_provider_login_when_null() {
245     organizationFlags.setEnabled(true);
246     UserIdentity newUser = UserIdentity.builder()
247       .setProviderId(null)
248       .setLogin("john")
249       .setProviderLogin("johndoo")
250       .setName("JOhn")
251       .build();
252
253     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
254       .setUserIdentity(newUser)
255       .setProvider(IDENTITY_PROVIDER)
256       .setSource(Source.local(BASIC))
257       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
258       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
259       .build());
260
261     assertThat(db.users().selectUserByLogin(newUser.getLogin()).get())
262       .extracting(UserDto::getLogin, UserDto::getExternalId, UserDto::getExternalLogin)
263       .contains("john", "johndoo", "johndoo");
264   }
265
266   @Test
267   public void authenticate_new_user_update_existing_user_email_when_strategy_is_ALLOW() {
268     organizationFlags.setEnabled(true);
269     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
270     UserIdentity newUser = UserIdentity.builder()
271       .setProviderLogin("johndoo")
272       .setLogin("new_login")
273       .setName(existingUser.getName())
274       .setEmail(existingUser.getEmail())
275       .build();
276
277     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
278       .setUserIdentity(newUser)
279       .setProvider(IDENTITY_PROVIDER)
280       .setSource(Source.local(BASIC))
281       .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
282       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
283       .build());
284
285     UserDto newUserReloaded = db.users().selectUserByLogin(newUser.getLogin()).get();
286     assertThat(newUserReloaded.getEmail()).isEqualTo(existingUser.getEmail());
287     UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get();
288     assertThat(existingUserReloaded.getEmail()).isNull();
289   }
290
291   @Test
292   public void throw_EmailAlreadyExistException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_WARN() {
293     organizationFlags.setEnabled(true);
294     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
295     UserIdentity newUser = UserIdentity.builder()
296       .setProviderLogin("johndoo")
297       .setLogin("new_login")
298       .setName(existingUser.getName())
299       .setEmail(existingUser.getEmail())
300       .build();
301
302     expectedException.expect(EmailAlreadyExistsRedirectionException.class);
303
304     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
305       .setUserIdentity(newUser)
306       .setProvider(IDENTITY_PROVIDER)
307       .setSource(Source.local(BASIC))
308       .setExistingEmailStrategy(ExistingEmailStrategy.WARN)
309       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
310       .build());
311   }
312
313   @Test
314   public void throw_AuthenticationException_when_authenticating_new_user_when_email_already_exists_and_strategy_is_FORBID() {
315     db.users().insertUser(u -> u.setEmail("john@email.com"));
316     Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
317
318     expectedException.expect(authenticationException().from(source)
319       .withLogin(USER_IDENTITY.getProviderLogin())
320       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
321         "This means that you probably already registered with another account."));
322     expectedException.expectMessage("Email 'john@email.com' is already used");
323
324     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
325       .setUserIdentity(USER_IDENTITY)
326       .setProvider(IDENTITY_PROVIDER)
327       .setSource(source)
328       .setExistingEmailStrategy(FORBID)
329       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
330       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
331       .build());
332   }
333
334   @Test
335   public void throw_AuthenticationException_when_authenticating_new_user_and_email_already_exists_multiple_times() {
336     db.users().insertUser(u -> u.setEmail("john@email.com"));
337     db.users().insertUser(u -> u.setEmail("john@email.com"));
338     Source source = Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName());
339
340     expectedException.expect(authenticationException().from(source)
341       .withLogin(USER_IDENTITY.getProviderLogin())
342       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
343         "This means that you probably already registered with another account."));
344     expectedException.expectMessage("Email 'john@email.com' is already used");
345
346     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
347       .setUserIdentity(USER_IDENTITY)
348       .setProvider(IDENTITY_PROVIDER)
349       .setSource(source)
350       .setExistingEmailStrategy(FORBID)
351       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
352       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
353       .build());
354   }
355
356   @Test
357   public void fail_to_authenticate_new_user_when_allow_users_to_signup_is_false() {
358     TestIdentityProvider identityProvider = new TestIdentityProvider()
359       .setKey("github")
360       .setName("Github")
361       .setEnabled(true)
362       .setAllowsUsersToSignUp(false);
363     Source source = Source.realm(AuthenticationEvent.Method.FORM, identityProvider.getName());
364
365     expectedException.expect(authenticationException().from(source).withLogin(USER_IDENTITY.getProviderLogin()).andPublicMessage("'github' users are not allowed to sign up"));
366     expectedException.expectMessage("User signup disabled for provider 'github'");
367
368     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
369       .setUserIdentity(USER_IDENTITY)
370       .setProvider(identityProvider)
371       .setSource(source)
372       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
373       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
374       .build());
375   }
376
377   @Test
378   public void authenticate_and_update_existing_user_matching_login() {
379     db.users().insertUser(u -> u
380       .setLogin(USER_LOGIN)
381       .setName("Old name")
382       .setEmail("Old email")
383       .setExternalId("old id")
384       .setExternalLogin("old identity")
385       .setExternalIdentityProvider("old provide"));
386
387     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
388       .setUserIdentity(USER_IDENTITY)
389       .setProvider(IDENTITY_PROVIDER)
390       .setSource(Source.local(BASIC))
391       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
392       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
393       .build());
394
395     assertThat(db.users().selectUserByLogin(USER_LOGIN).get())
396       .extracting(UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider, UserDto::isActive)
397       .contains("John", "john@email.com", "ABCD", "johndoo", "github", true);
398   }
399
400   @Test
401   public void authenticate_and_update_existing_user_matching_external_id() {
402     UserDto user = db.users().insertUser(u -> u
403       .setLogin("Old login")
404       .setName("Old name")
405       .setEmail("Old email")
406       .setExternalId(USER_IDENTITY.getProviderId())
407       .setExternalLogin("old identity")
408       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
409
410     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
411       .setUserIdentity(USER_IDENTITY)
412       .setProvider(IDENTITY_PROVIDER)
413       .setSource(Source.local(BASIC))
414       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
415       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
416       .build());
417
418     assertThat(db.users().selectUserByLogin("Old login")).isNotPresent();
419     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
420       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
421         UserDto::isActive)
422       .contains(USER_LOGIN, "John", "john@email.com", "ABCD", "johndoo", "github", true);
423   }
424
425   @Test
426   public void authenticate_existing_user_and_update_only_login() {
427     UserDto user = db.users().insertUser(u -> u
428       .setLogin("old login")
429       .setName(USER_IDENTITY.getName())
430       .setEmail(USER_IDENTITY.getEmail())
431       .setExternalId(USER_IDENTITY.getProviderId())
432       .setExternalLogin("old identity")
433       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
434
435     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
436       .setUserIdentity(USER_IDENTITY)
437       .setProvider(IDENTITY_PROVIDER)
438       .setSource(Source.local(BASIC))
439       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
440       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
441       .build());
442
443     assertThat(db.users().selectUserByLogin("Old login")).isNotPresent();
444     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
445       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
446         UserDto::isActive)
447       .containsExactlyInAnyOrder(USER_LOGIN, USER_IDENTITY.getName(), USER_IDENTITY.getEmail(), USER_IDENTITY.getProviderId(), USER_IDENTITY.getProviderLogin(),
448         IDENTITY_PROVIDER.getKey(),
449         true);
450   }
451
452   @Test
453   public void authenticate_existing_user_and_update_only_identity_provider_key() {
454     UserDto user = db.users().insertUser(u -> u
455       .setLogin(USER_LOGIN)
456       .setName(USER_IDENTITY.getName())
457       .setEmail(USER_IDENTITY.getEmail())
458       .setExternalId(USER_IDENTITY.getProviderId())
459       .setExternalLogin(USER_IDENTITY.getProviderLogin())
460       .setExternalIdentityProvider("old identity provider"));
461
462     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
463       .setUserIdentity(USER_IDENTITY)
464       .setProvider(IDENTITY_PROVIDER)
465       .setSource(Source.local(BASIC))
466       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
467       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
468       .build());
469
470     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
471       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
472         UserDto::isActive)
473       .containsExactlyInAnyOrder(USER_LOGIN, USER_IDENTITY.getName(), USER_IDENTITY.getEmail(), USER_IDENTITY.getProviderId(), USER_IDENTITY.getProviderLogin(),
474         IDENTITY_PROVIDER.getKey(),
475         true);
476   }
477
478   @Test
479   public void authenticate_existing_user_matching_login_when_external_id_is_null() {
480     UserDto user = db.users().insertUser(u -> u
481       .setLogin(USER_LOGIN)
482       .setName("Old name")
483       .setEmail("Old email")
484       .setExternalId("Old id")
485       .setExternalLogin("old identity")
486       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
487
488     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
489       .setUserIdentity(UserIdentity.builder()
490         .setProviderId(null)
491         .setProviderLogin("johndoo")
492         .setLogin(USER_LOGIN)
493         .setName("John")
494         .setEmail("john@email.com")
495         .build())
496       .setProvider(IDENTITY_PROVIDER)
497       .setSource(Source.local(BASIC))
498       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
499       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
500       .build());
501
502     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
503       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
504         UserDto::isActive)
505       .contains(user.getLogin(), "John", "john@email.com", "johndoo", "johndoo", "github", true);
506   }
507
508   @Test
509   public void authenticate_existing_user_when_login_is_not_provided() {
510     UserDto user = db.users().insertUser(u -> u.setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
511
512     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
513       .setUserIdentity(UserIdentity.builder()
514         .setProviderId(user.getExternalId())
515         .setProviderLogin(user.getExternalLogin())
516         // No login provided
517         .setName(user.getName())
518         .setEmail(user.getEmail())
519         .build())
520       .setProvider(IDENTITY_PROVIDER)
521       .setSource(Source.local(BASIC))
522       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
523       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
524       .build());
525
526     // No new user is created
527     assertThat(db.countRowsOfTable(db.getSession(), "users")).isEqualTo(1);
528     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
529       .extracting(UserDto::getLogin, UserDto::getName, UserDto::getEmail, UserDto::getExternalId, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider,
530         UserDto::isActive)
531       .contains(user.getLogin(), user.getName(), user.getEmail(), user.getExternalId(), user.getExternalLogin(), user.getExternalIdentityProvider(), true);
532   }
533
534   @Test
535   public void authenticate_existing_user_with_login_update_and_strategy_is_ALLOW() {
536     UserDto user = db.users().insertUser(u -> u
537       .setLogin("Old login")
538       .setExternalId(USER_IDENTITY.getProviderId())
539       .setExternalLogin("old identity")
540       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
541
542     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
543       .setUserIdentity(USER_IDENTITY)
544       .setProvider(IDENTITY_PROVIDER)
545       .setSource(Source.local(BASIC))
546       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
547       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
548       .build());
549
550     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
551       .extracting(UserDto::getLogin, UserDto::getExternalLogin)
552       .contains(USER_LOGIN, USER_IDENTITY.getProviderLogin());
553   }
554
555   @Test
556   public void authenticate_existing_user_with_login_update_and_personal_org_does_not_exits_and_strategy_is_WARN() {
557     organizationFlags.setEnabled(true);
558     UserDto user = db.users().insertUser(u -> u
559       .setLogin("Old login")
560       .setExternalId(USER_IDENTITY.getProviderId())
561       .setExternalLogin("old identity")
562       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
563       .setOrganizationUuid(null));
564
565     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
566       .setUserIdentity(USER_IDENTITY)
567       .setProvider(IDENTITY_PROVIDER)
568       .setSource(Source.local(BASIC))
569       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
570       .setUpdateLoginStrategy(UpdateLoginStrategy.WARN)
571       .build());
572
573     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
574       .extracting(UserDto::getLogin, UserDto::getExternalLogin)
575       .contains(USER_LOGIN, USER_IDENTITY.getProviderLogin());
576   }
577
578   @Test
579   public void throw_UpdateLoginRedirectionException_when_authenticating_with_login_update_and_personal_org_exists_and_strategy_is_WARN() {
580     organizationFlags.setEnabled(true);
581     OrganizationDto organization = db.organizations().insert(o -> o.setKey("Old login"));
582     db.users().insertUser(u -> u
583       .setLogin("Old login")
584       .setExternalId(USER_IDENTITY.getProviderId())
585       .setExternalLogin("old identity")
586       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
587       .setOrganizationUuid(organization.getUuid()));
588
589     expectedException.expect(UpdateLoginRedirectionException.class);
590
591     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
592       .setUserIdentity(USER_IDENTITY)
593       .setProvider(IDENTITY_PROVIDER)
594       .setSource(Source.local(BASIC))
595       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
596       .setUpdateLoginStrategy(UpdateLoginStrategy.WARN)
597       .build());
598   }
599
600   @Test
601   public void authenticate_existing_user_and_update_personal_og_key_when_personal_org_exists_and_strategy_is_ALLOW() {
602     organizationFlags.setEnabled(true);
603     OrganizationDto personalOrganization = db.organizations().insert(o -> o.setKey("Old login"));
604     UserDto user = db.users().insertUser(u -> u
605       .setLogin("Old login")
606       .setExternalId(USER_IDENTITY.getProviderId())
607       .setExternalLogin("old identity")
608       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
609       .setOrganizationUuid(personalOrganization.getUuid()));
610
611     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
612       .setUserIdentity(USER_IDENTITY)
613       .setProvider(IDENTITY_PROVIDER)
614       .setSource(Source.local(BASIC))
615       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
616       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
617       .build());
618
619     assertThat(db.getDbClient().userDao().selectByUuid(db.getSession(), user.getUuid()))
620       .extracting(UserDto::getLogin, UserDto::getExternalLogin)
621       .contains(USER_LOGIN, USER_IDENTITY.getProviderLogin());
622     OrganizationDto organizationReloaded = db.getDbClient().organizationDao().selectByUuid(db.getSession(), personalOrganization.getUuid()).get();
623     assertThat(organizationReloaded.getKey()).isEqualTo(USER_LOGIN);
624   }
625
626   @Test
627   public void fail_to_authenticate_existing_user_when_personal_org_does_not_exist() {
628     organizationFlags.setEnabled(true);
629     db.users().insertUser(u -> u
630       .setLogin("Old login")
631       .setExternalId(USER_IDENTITY.getProviderId())
632       .setExternalLogin("old identity")
633       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey())
634       .setOrganizationUuid("unknown"));
635
636     expectedException.expect(IllegalStateException.class);
637     expectedException.expectMessage("Cannot find personal organization uuid 'unknown' for user 'Old login'");
638
639     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
640       .setUserIdentity(USER_IDENTITY)
641       .setProvider(IDENTITY_PROVIDER)
642       .setSource(Source.local(BASIC))
643       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
644       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
645       .build());
646   }
647
648   @Test
649   public void authenticate_existing_disabled_user() {
650     organizationFlags.setEnabled(true);
651     db.users().insertUser(u -> u
652       .setLogin(USER_LOGIN)
653       .setActive(false)
654       .setName("Old name")
655       .setEmail("Old email")
656       .setExternalId("old id")
657       .setExternalLogin("old identity")
658       .setExternalIdentityProvider("old provide"));
659
660     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
661       .setUserIdentity(USER_IDENTITY)
662       .setProvider(IDENTITY_PROVIDER)
663       .setSource(Source.local(BASIC))
664       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
665       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
666       .build());
667
668     UserDto userDto = db.users().selectUserByLogin(USER_LOGIN).get();
669     assertThat(userDto.isActive()).isTrue();
670     assertThat(userDto.getName()).isEqualTo("John");
671     assertThat(userDto.getEmail()).isEqualTo("john@email.com");
672     assertThat(userDto.getExternalId()).isEqualTo("ABCD");
673     assertThat(userDto.getExternalLogin()).isEqualTo("johndoo");
674     assertThat(userDto.getExternalIdentityProvider()).isEqualTo("github");
675     assertThat(userDto.isRoot()).isFalse();
676   }
677
678   @Test
679   public void authenticate_existing_user_when_email_already_exists_and_strategy_is_ALLOW() {
680     organizationFlags.setEnabled(true);
681     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
682     UserDto currentUser = db.users().insertUser(u -> u.setEmail(null));
683     UserIdentity userIdentity = UserIdentity.builder()
684       .setLogin(currentUser.getLogin())
685       .setProviderLogin("johndoo")
686       .setName("John")
687       .setEmail("john@email.com")
688       .build();
689
690     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
691       .setUserIdentity(userIdentity)
692       .setProvider(IDENTITY_PROVIDER)
693       .setSource(Source.local(BASIC))
694       .setExistingEmailStrategy(ExistingEmailStrategy.ALLOW)
695       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
696       .build());
697
698     UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get();
699     assertThat(currentUserReloaded.getEmail()).isEqualTo("john@email.com");
700     UserDto existingUserReloaded = db.users().selectUserByLogin(existingUser.getLogin()).get();
701     assertThat(existingUserReloaded.getEmail()).isNull();
702   }
703
704   @Test
705   public void throw_EmailAlreadyExistException_when_authenticating_existing_user_when_email_already_exists_and_strategy_is_WARN() {
706     organizationFlags.setEnabled(true);
707     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
708     UserDto currentUser = db.users().insertUser(u -> u.setEmail(null));
709     UserIdentity userIdentity = UserIdentity.builder()
710       .setLogin(currentUser.getLogin())
711       .setProviderLogin("johndoo")
712       .setName("John")
713       .setEmail("john@email.com")
714       .build();
715
716     expectedException.expect(EmailAlreadyExistsRedirectionException.class);
717
718     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
719       .setUserIdentity(userIdentity)
720       .setProvider(IDENTITY_PROVIDER)
721       .setSource(Source.local(BASIC))
722       .setExistingEmailStrategy(ExistingEmailStrategy.WARN)
723       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
724       .build());
725   }
726
727   @Test
728   public void throw_AuthenticationException_when_authenticating_existing_user_when_email_already_exists_and_strategy_is_FORBID() {
729     organizationFlags.setEnabled(true);
730     UserDto existingUser = db.users().insertUser(u -> u.setEmail("john@email.com"));
731     UserDto currentUser = db.users().insertUser(u -> u.setEmail(null));
732     UserIdentity userIdentity = UserIdentity.builder()
733       .setLogin(currentUser.getLogin())
734       .setProviderLogin("johndoo")
735       .setName("John")
736       .setEmail("john@email.com")
737       .build();
738
739     expectedException.expect(authenticationException().from(Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName()))
740       .withLogin(userIdentity.getProviderLogin())
741       .andPublicMessage("You can't sign up because email 'john@email.com' is already used by an existing user. " +
742         "This means that you probably already registered with another account."));
743     expectedException.expectMessage("Email 'john@email.com' is already used");
744
745     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
746       .setUserIdentity(userIdentity)
747       .setProvider(IDENTITY_PROVIDER)
748       .setSource(Source.realm(AuthenticationEvent.Method.FORM, IDENTITY_PROVIDER.getName()))
749       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
750       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
751       .build());
752   }
753
754   @Test
755   public void does_not_fail_to_authenticate_user_when_email_has_not_changed_and_strategy_is_FORBID() {
756     organizationFlags.setEnabled(true);
757     UserDto currentUser = db.users().insertUser(u -> u.setEmail("john@email.com")
758       .setExternalIdentityProvider(IDENTITY_PROVIDER.getKey()));
759     UserIdentity userIdentity = UserIdentity.builder()
760       .setLogin(currentUser.getLogin())
761       .setProviderId(currentUser.getExternalId())
762       .setProviderLogin(currentUser.getExternalLogin())
763       .setName("John")
764       .setEmail("john@email.com")
765       .build();
766
767     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
768       .setUserIdentity(userIdentity)
769       .setProvider(IDENTITY_PROVIDER)
770       .setSource(Source.local(BASIC))
771       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
772       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
773       .build());
774
775     UserDto currentUserReloaded = db.users().selectUserByLogin(currentUser.getLogin()).get();
776     assertThat(currentUserReloaded.getEmail()).isEqualTo("john@email.com");
777   }
778
779   @Test
780   public void authenticate_existing_user_and_add_new_groups() {
781     organizationFlags.setEnabled(true);
782     UserDto user = db.users().insertUser(newUserDto()
783       .setLogin(USER_LOGIN)
784       .setActive(true)
785       .setName("John"));
786     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
787     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
788
789     authenticate(USER_LOGIN, "group1", "group2", "group3");
790
791     checkGroupMembership(user, group1, group2);
792   }
793
794   @Test
795   public void authenticate_existing_user_and_remove_groups() {
796     organizationFlags.setEnabled(true);
797     UserDto user = db.users().insertUser(newUserDto()
798       .setLogin(USER_LOGIN)
799       .setActive(true)
800       .setName("John"));
801     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
802     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
803     db.users().insertMember(group1, user);
804     db.users().insertMember(group2, user);
805
806     authenticate(USER_LOGIN, "group1");
807
808     checkGroupMembership(user, group1);
809   }
810
811   @Test
812   public void authenticate_existing_user_and_remove_all_groups_expect_default_when_organizations_are_disabled() {
813     organizationFlags.setEnabled(false);
814     UserDto user = db.users().insertUser();
815     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
816     GroupDto group2 = db.users().insertGroup(db.getDefaultOrganization(), "group2");
817     GroupDto defaultGroup = insertDefaultGroup();
818     db.users().insertMember(group1, user);
819     db.users().insertMember(group2, user);
820     db.users().insertMember(defaultGroup, user);
821
822     authenticate(user.getLogin());
823
824     checkGroupMembership(user, defaultGroup);
825   }
826
827   @Test
828   public void does_not_force_default_group_when_authenticating_existing_user_when_organizations_are_enabled() {
829     organizationFlags.setEnabled(true);
830     UserDto user = db.users().insertUser();
831     GroupDto group1 = db.users().insertGroup(db.getDefaultOrganization(), "group1");
832     GroupDto defaultGroup = insertDefaultGroup();
833     db.users().insertMember(group1, user);
834     db.users().insertMember(defaultGroup, user);
835
836     authenticate(user.getLogin(), "group1");
837
838     checkGroupMembership(user, group1);
839   }
840
841   @Test
842   public void ignore_groups_on_non_default_organizations() {
843     organizationFlags.setEnabled(true);
844     OrganizationDto org = db.organizations().insert();
845     UserDto user = db.users().insertUser(newUserDto()
846       .setLogin(USER_LOGIN)
847       .setActive(true)
848       .setName("John"));
849     String groupName = "a-group";
850     GroupDto groupInDefaultOrg = db.users().insertGroup(db.getDefaultOrganization(), groupName);
851     GroupDto groupInOrg = db.users().insertGroup(org, groupName);
852
853     // adding a group with the same name than in non-default organization
854     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
855       .setUserIdentity(UserIdentity.builder()
856         .setProviderLogin("johndoo")
857         .setLogin(user.getLogin())
858         .setName(user.getName())
859         .setGroups(newHashSet(groupName))
860         .build())
861       .setProvider(IDENTITY_PROVIDER)
862       .setSource(Source.local(BASIC))
863       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
864       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
865       .build());
866
867     checkGroupMembership(user, groupInDefaultOrg);
868   }
869
870   private void authenticate(String login, String... groups) {
871     underTest.authenticate(UserIdentityAuthenticatorParameters.builder()
872       .setUserIdentity(UserIdentity.builder()
873         .setProviderLogin("johndoo")
874         .setLogin(login)
875         .setName("John")
876         // No group
877         .setGroups(stream(groups).collect(MoreCollectors.toSet()))
878         .build())
879       .setProvider(IDENTITY_PROVIDER)
880       .setSource(Source.local(BASIC))
881       .setExistingEmailStrategy(ExistingEmailStrategy.FORBID)
882       .setUpdateLoginStrategy(UpdateLoginStrategy.ALLOW)
883       .build());
884   }
885
886   private void checkGroupMembership(UserDto user, GroupDto... expectedGroups) {
887     assertThat(db.users().selectGroupIdsOfUser(user)).containsOnly(stream(expectedGroups).map(GroupDto::getId).collect(Collectors.toList()).toArray(new Integer[] {}));
888   }
889
890   private GroupDto insertDefaultGroup() {
891     return db.users().insertDefaultGroup(db.getDefaultOrganization(), "sonar-users");
892   }
893
894 }