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.

CreateActionTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.user.ws;
  21. import java.util.HashSet;
  22. import java.util.Optional;
  23. import org.junit.Before;
  24. import org.junit.Rule;
  25. import org.junit.Test;
  26. import org.junit.rules.ExpectedException;
  27. import org.mockito.ArgumentCaptor;
  28. import org.sonar.api.config.internal.MapSettings;
  29. import org.sonar.api.server.ws.WebService;
  30. import org.sonar.api.utils.System2;
  31. import org.sonar.api.utils.internal.AlwaysIncreasingSystem2;
  32. import org.sonar.core.config.CorePropertyDefinitions;
  33. import org.sonar.db.DbSession;
  34. import org.sonar.db.DbTester;
  35. import org.sonar.db.user.GroupDto;
  36. import org.sonar.db.user.UserDto;
  37. import org.sonar.server.authentication.CredentialsLocalAuthentication;
  38. import org.sonar.server.es.EsTester;
  39. import org.sonar.server.exceptions.ForbiddenException;
  40. import org.sonar.server.organization.DefaultOrganizationProvider;
  41. import org.sonar.server.organization.OrganizationUpdater;
  42. import org.sonar.server.organization.TestDefaultOrganizationProvider;
  43. import org.sonar.server.organization.TestOrganizationFlags;
  44. import org.sonar.server.tester.UserSessionRule;
  45. import org.sonar.server.user.NewUserNotifier;
  46. import org.sonar.server.user.UserUpdater;
  47. import org.sonar.server.user.index.UserIndexDefinition;
  48. import org.sonar.server.user.index.UserIndexer;
  49. import org.sonar.server.user.ws.CreateAction.CreateRequest;
  50. import org.sonar.server.usergroups.DefaultGroupFinder;
  51. import org.sonar.server.ws.TestRequest;
  52. import org.sonar.server.ws.WsActionTester;
  53. import org.sonarqube.ws.Users.CreateWsResponse;
  54. import org.sonarqube.ws.Users.CreateWsResponse.User;
  55. import static java.lang.String.format;
  56. import static java.util.Collections.singletonList;
  57. import static java.util.Optional.ofNullable;
  58. import static org.assertj.core.api.Assertions.assertThat;
  59. import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
  60. import static org.elasticsearch.index.query.QueryBuilders.termQuery;
  61. import static org.mockito.ArgumentMatchers.any;
  62. import static org.mockito.Mockito.mock;
  63. import static org.mockito.Mockito.verify;
  64. import static org.sonar.db.user.UserTesting.newUserDto;
  65. import static org.sonar.server.user.index.UserIndexDefinition.FIELD_EMAIL;
  66. import static org.sonar.server.user.index.UserIndexDefinition.FIELD_LOGIN;
  67. import static org.sonar.server.user.index.UserIndexDefinition.FIELD_NAME;
  68. import static org.sonar.server.user.index.UserIndexDefinition.FIELD_SCM_ACCOUNTS;
  69. public class CreateActionTest {
  70. private static final String DEFAULT_GROUP_NAME = "sonar-users";
  71. private MapSettings settings = new MapSettings();
  72. private System2 system2 = new AlwaysIncreasingSystem2();
  73. @Rule
  74. public DbTester db = DbTester.create(system2);
  75. @Rule
  76. public EsTester es = EsTester.create();
  77. @Rule
  78. public UserSessionRule userSessionRule = UserSessionRule.standalone();
  79. @Rule
  80. public ExpectedException expectedException = ExpectedException.none();
  81. private UserIndexer userIndexer = new UserIndexer(db.getDbClient(), es.client());
  82. private GroupDto defaultGroupInDefaultOrg;
  83. private DefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
  84. private TestOrganizationFlags organizationFlags = TestOrganizationFlags.standalone();
  85. private OrganizationUpdater organizationUpdater = mock(OrganizationUpdater.class);
  86. private CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(db.getDbClient());
  87. private WsActionTester tester = new WsActionTester(new CreateAction(
  88. db.getDbClient(),
  89. new UserUpdater(system2, mock(NewUserNotifier.class), db.getDbClient(), userIndexer, organizationFlags, defaultOrganizationProvider,
  90. organizationUpdater, new DefaultGroupFinder(db.getDbClient()), settings.asConfig(), localAuthentication),
  91. userSessionRule));
  92. @Before
  93. public void setUp() {
  94. defaultGroupInDefaultOrg = db.users().insertDefaultGroup(db.getDefaultOrganization(), DEFAULT_GROUP_NAME);
  95. }
  96. @Test
  97. public void create_user() {
  98. logInAsSystemAdministrator();
  99. CreateWsResponse response = call(CreateRequest.builder()
  100. .setLogin("john")
  101. .setName("John")
  102. .setEmail("john@email.com")
  103. .setScmAccounts(singletonList("jn"))
  104. .setPassword("1234")
  105. .build());
  106. assertThat(response.getUser())
  107. .extracting(User::getLogin, User::getName, User::getEmail, User::getScmAccountsList, User::getLocal)
  108. .containsOnly("john", "John", "john@email.com", singletonList("jn"), true);
  109. // exists in index
  110. assertThat(es.client().prepareSearch(UserIndexDefinition.TYPE_USER)
  111. .setQuery(boolQuery()
  112. .must(termQuery(FIELD_LOGIN, "john"))
  113. .must(termQuery(FIELD_NAME, "John"))
  114. .must(termQuery(FIELD_EMAIL, "john@email.com"))
  115. .must(termQuery(FIELD_SCM_ACCOUNTS, "jn")))
  116. .get().getHits().getHits()).hasSize(1);
  117. // exists in db
  118. Optional<UserDto> dbUser = db.users().selectUserByLogin("john");
  119. assertThat(dbUser).isPresent();
  120. assertThat(dbUser.get().isRoot()).isFalse();
  121. // member of default group in default organization
  122. assertThat(db.users().selectGroupIdsOfUser(dbUser.get())).containsOnly(defaultGroupInDefaultOrg.getId());
  123. }
  124. @Test
  125. public void create_user_calls_create_personal_organization_if_personal_organizations_are_enabled() {
  126. logInAsSystemAdministrator();
  127. enableCreatePersonalOrg(true);
  128. assertACallToOrganizationCreationWhenUserIsCreated();
  129. }
  130. @Test
  131. public void create_user_calls_create_personal_organization_if_personal_organizations_are_disabled() {
  132. logInAsSystemAdministrator();
  133. enableCreatePersonalOrg(false);
  134. assertACallToOrganizationCreationWhenUserIsCreated();
  135. }
  136. @Test
  137. public void create_user_associates_him_to_default_organization() {
  138. logInAsSystemAdministrator();
  139. enableCreatePersonalOrg(true);
  140. call(CreateRequest.builder()
  141. .setLogin("john")
  142. .setName("John")
  143. .setPassword("1234")
  144. .build());
  145. Optional<UserDto> dbUser = db.users().selectUserByLogin("john");
  146. assertThat(dbUser).isPresent();
  147. assertThat(db.getDbClient().organizationMemberDao().select(db.getSession(), defaultOrganizationProvider.get().getUuid(), dbUser.get().getId())).isPresent();
  148. }
  149. @Test
  150. public void create_local_user() {
  151. logInAsSystemAdministrator();
  152. call(CreateRequest.builder()
  153. .setLogin("john")
  154. .setName("John")
  155. .setPassword("1234")
  156. .setLocal(true)
  157. .build());
  158. assertThat(db.users().selectUserByLogin("john").get())
  159. .extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalLogin, UserDto::isRoot)
  160. .containsOnly(true, "sonarqube", "john", false);
  161. }
  162. @Test
  163. public void create_none_local_user() {
  164. logInAsSystemAdministrator();
  165. call(CreateRequest.builder()
  166. .setLogin("john")
  167. .setName("John")
  168. .setLocal(false)
  169. .build());
  170. assertThat(db.users().selectUserByLogin("john").get())
  171. .extracting(UserDto::isLocal, UserDto::getExternalIdentityProvider, UserDto::getExternalLogin, UserDto::isRoot)
  172. .containsOnly(false, "sonarqube", "john", false);
  173. }
  174. @Test
  175. public void create_user_with_comma_in_scm_account() {
  176. logInAsSystemAdministrator();
  177. CreateWsResponse response = call(CreateRequest.builder()
  178. .setLogin("john")
  179. .setName("John")
  180. .setEmail("john@email.com")
  181. .setScmAccounts(singletonList("j,n"))
  182. .setPassword("1234")
  183. .build());
  184. assertThat(response.getUser().getScmAccountsList()).containsOnly("j,n");
  185. }
  186. @Test
  187. public void create_user_with_empty_email() {
  188. logInAsSystemAdministrator();
  189. call(CreateRequest.builder()
  190. .setLogin("john")
  191. .setName("John")
  192. .setPassword("1234")
  193. .setEmail("")
  194. .build());
  195. assertThat(db.users().selectUserByLogin("john").get())
  196. .extracting(UserDto::getExternalLogin)
  197. .containsOnly("john");
  198. }
  199. @Test
  200. public void create_user_with_deprecated_scmAccounts_parameter() {
  201. logInAsSystemAdministrator();
  202. tester.newRequest()
  203. .setParam("login", "john")
  204. .setParam("name", "John")
  205. .setParam("password", "1234")
  206. .setParam("scmAccounts", "jn")
  207. .execute();
  208. assertThat(db.users().selectUserByLogin("john").get().getScmAccountsAsList()).containsOnly("jn");
  209. }
  210. @Test
  211. public void create_user_with_deprecated_scm_accounts_parameter() {
  212. logInAsSystemAdministrator();
  213. tester.newRequest()
  214. .setParam("login", "john")
  215. .setParam("name", "John")
  216. .setParam("password", "1234")
  217. .setParam("scm_accounts", "jn")
  218. .execute();
  219. assertThat(db.users().selectUserByLogin("john").get().getScmAccountsAsList()).containsOnly("jn");
  220. }
  221. @Test
  222. public void reactivate_user() {
  223. logInAsSystemAdministrator();
  224. db.users().insertUser(newUserDto("john", "John", "john@email.com").setActive(false));
  225. userIndexer.indexOnStartup(new HashSet<>());
  226. call(CreateRequest.builder()
  227. .setLogin("john")
  228. .setName("John")
  229. .setEmail("john@email.com")
  230. .setScmAccounts(singletonList("jn"))
  231. .setPassword("1234")
  232. .build());
  233. assertThat(db.users().selectUserByLogin("john").get().isActive()).isTrue();
  234. }
  235. @Test
  236. public void fail_to_reactivate_user_when_active_user_exists() {
  237. logInAsSystemAdministrator();
  238. UserDto user = db.users().insertUser();
  239. expectedException.expect(IllegalArgumentException.class);
  240. expectedException.expectMessage(format("An active user with login '%s' already exists", user.getLogin()));
  241. call(CreateRequest.builder()
  242. .setLogin(user.getLogin())
  243. .setName("John")
  244. .setPassword("1234")
  245. .build());
  246. }
  247. @Test
  248. public void fail_when_missing_login() {
  249. logInAsSystemAdministrator();
  250. expectedException.expect(IllegalArgumentException.class);
  251. expectedException.expectMessage("Login is mandatory and must not be empty");
  252. call(CreateRequest.builder()
  253. .setLogin(null)
  254. .setName("John")
  255. .setPassword("1234")
  256. .build());
  257. }
  258. @Test
  259. public void fail_when_login_is_too_short() {
  260. logInAsSystemAdministrator();
  261. expectedException.expect(IllegalArgumentException.class);
  262. expectedException.expectMessage("'login' length (1) is shorter than the minimum authorized (2)");
  263. call(CreateRequest.builder()
  264. .setLogin("a")
  265. .setName("John")
  266. .setPassword("1234")
  267. .build());
  268. }
  269. @Test
  270. public void fail_when_missing_name() {
  271. logInAsSystemAdministrator();
  272. expectedException.expect(IllegalArgumentException.class);
  273. expectedException.expectMessage("Name is mandatory and must not be empty");
  274. call(CreateRequest.builder()
  275. .setLogin("john")
  276. .setName(null)
  277. .setPassword("1234")
  278. .build());
  279. }
  280. @Test
  281. public void fail_when_missing_password() {
  282. logInAsSystemAdministrator();
  283. expectedException.expect(IllegalArgumentException.class);
  284. expectedException.expectMessage("Password is mandatory and must not be empty");
  285. call(CreateRequest.builder()
  286. .setLogin("john")
  287. .setName("John")
  288. .setPassword(null)
  289. .build());
  290. }
  291. @Test
  292. public void fail_when_password_is_set_on_none_local_user() {
  293. logInAsSystemAdministrator();
  294. expectedException.expect(IllegalArgumentException.class);
  295. expectedException.expectMessage("Password should only be set on local user");
  296. call(CreateRequest.builder()
  297. .setLogin("john")
  298. .setName("John")
  299. .setPassword("1234")
  300. .setLocal(false)
  301. .build());
  302. }
  303. @Test
  304. public void fail_when_email_is_invalid() {
  305. logInAsSystemAdministrator();
  306. expectedException.expect(IllegalArgumentException.class);
  307. expectedException.expectMessage("Email 'invalid-email' is not valid");
  308. call(CreateRequest.builder()
  309. .setLogin("pipo")
  310. .setName("John")
  311. .setPassword("1234")
  312. .setEmail("invalid-email")
  313. .build());
  314. }
  315. @Test
  316. public void throw_ForbiddenException_if_not_system_administrator() {
  317. userSessionRule.logIn().setNonSystemAdministrator();
  318. expectedException.expect(ForbiddenException.class);
  319. expectedException.expectMessage("");
  320. expectedException.expect(ForbiddenException.class);
  321. executeRequest("john");
  322. }
  323. @Test
  324. public void test_definition() {
  325. WebService.Action action = tester.getDef();
  326. assertThat(action).isNotNull();
  327. assertThat(action.isPost()).isTrue();
  328. assertThat(action.params()).hasSize(7);
  329. }
  330. private CreateWsResponse executeRequest(String login) {
  331. return call(CreateRequest.builder()
  332. .setLogin(login)
  333. .setName("name of " + login)
  334. .setEmail(login + "@email.com")
  335. .setScmAccounts(singletonList(login.substring(0, 2)))
  336. .setPassword("pwd_" + login)
  337. .build());
  338. }
  339. private void assertACallToOrganizationCreationWhenUserIsCreated() {
  340. call(CreateRequest.builder()
  341. .setLogin("john")
  342. .setName("John")
  343. .setPassword("1234")
  344. .build());
  345. Optional<UserDto> dbUser = db.users().selectUserByLogin("john");
  346. assertThat(dbUser).isPresent();
  347. ArgumentCaptor<UserDto> userCaptor = ArgumentCaptor.forClass(UserDto.class);
  348. verify(organizationUpdater).createForUser(any(DbSession.class), userCaptor.capture());
  349. assertThat(userCaptor.getValue().getId()).isEqualTo(dbUser.get().getId());
  350. }
  351. private void logInAsSystemAdministrator() {
  352. userSessionRule.logIn().setSystemAdministrator();
  353. }
  354. private CreateWsResponse call(CreateRequest createRequest) {
  355. TestRequest request = tester.newRequest();
  356. ofNullable(createRequest.getLogin()).ifPresent(e4 -> request.setParam("login", e4));
  357. ofNullable(createRequest.getName()).ifPresent(e3 -> request.setParam("name", e3));
  358. ofNullable(createRequest.getEmail()).ifPresent(e2 -> request.setParam("email", e2));
  359. ofNullable(createRequest.getPassword()).ifPresent(e1 -> request.setParam("password", e1));
  360. ofNullable(createRequest.getScmAccounts()).ifPresent(e -> request.setMultiParam("scmAccount", e));
  361. request.setParam("local", createRequest.isLocal() ? "true" : "false");
  362. return request.executeProtobuf(CreateWsResponse.class);
  363. }
  364. private void enableCreatePersonalOrg(boolean flag) {
  365. settings.setProperty(CorePropertyDefinitions.ORGANIZATIONS_CREATE_PERSONAL_ORG, flag);
  366. }
  367. }