You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UserRegistrarImplTest.java 29KB

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