diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-10-05 13:57:56 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-10-12 12:24:31 +0200 |
commit | c7c271638798905934be58f81365feba904a954f (patch) | |
tree | 220f168a73079d6e3c01324c5291e434a291d190 | |
parent | 9a2a008ff6fd46a758ed408f2957ac41ca5df5f0 (diff) | |
download | sonarqube-c7c271638798905934be58f81365feba904a954f.tar.gz sonarqube-c7c271638798905934be58f81365feba904a954f.zip |
SONAR-8191 last root can't be unset via /api/root/unset_root
6 files changed, 172 insertions, 20 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/root/ws/UnsetRootWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/root/ws/UnsetRootWsAction.java index 1dcf2b7b5f8..880bcaeae1c 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/root/ws/UnsetRootWsAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/root/ws/UnsetRootWsAction.java @@ -24,6 +24,7 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.db.DbClient; import org.sonar.db.DbSession; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.user.UserSession; public class UnsetRootWsAction implements RootWsAction { @@ -60,6 +61,9 @@ public class UnsetRootWsAction implements RootWsAction { String login = request.mandatoryParam(PARAM_LOGIN); try (DbSession dbSession = dbClient.openSession(false)) { + if (dbClient.userDao().countRootUsersButLogin(dbSession, login) == 0) { + throw new BadRequestException("Last root can't be unset"); + } dbClient.userDao().setRoot(dbSession, login, false); dbSession.commit(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/root/ws/UnsetRootWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/root/ws/UnsetRootWsActionTest.java index 140460f14c3..43c81df782a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/root/ws/UnsetRootWsActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/root/ws/UnsetRootWsActionTest.java @@ -29,13 +29,14 @@ import org.sonar.db.DbSession; import org.sonar.db.DbTester; import org.sonar.db.user.UserDao; import org.sonar.db.user.UserDto; -import org.sonar.db.user.UserTesting; +import org.sonar.server.exceptions.BadRequestException; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.TestRequest; import org.sonar.server.ws.WsActionTester; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.user.UserTesting.newUserDto; public class UnsetRootWsActionTest { private static final String SOME_LOGIN = "johndoe"; @@ -60,7 +61,7 @@ public class UnsetRootWsActionTest { assertThat(action.isPost()).isTrue(); assertThat(action.since()).isEqualTo("6.2"); assertThat(action.description()).isEqualTo("Make the specified user not root.<br/>" + - "Requires to be root."); + "Requires to be root."); assertThat(action.responseExample()).isNull(); assertThat(action.deprecatedKey()).isNull(); assertThat(action.deprecatedSince()).isNull(); @@ -94,7 +95,7 @@ public class UnsetRootWsActionTest { @Test public void execute_fails_with_IAE_when_login_param_is_not_provided() { - userSessionRule.login().setRoot(); + makeAuthenticatedUserRoot(); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("The 'login' parameter is missing"); @@ -104,13 +105,9 @@ public class UnsetRootWsActionTest { @Test public void execute_makes_user_with_specified_login_not_root_when_it_is() { - UserDto otherUser = UserTesting.newUserDto(); - userDao.insert(dbSession, otherUser); - userDao.setRoot(dbSession, otherUser.getLogin(), true); - userDao.insert(dbSession, UserTesting.newUserDto(SOME_LOGIN, "name", "email")); - userDao.setRoot(dbSession, SOME_LOGIN, true); - dbSession.commit(); - userSessionRule.login().setRoot(); + UserDto otherUser = insertRootUser(newUserDto()); + insertRootUser(newUserDto(SOME_LOGIN, "name", "email")); + makeAuthenticatedUserRoot(); executeRequest(SOME_LOGIN); @@ -120,13 +117,9 @@ public class UnsetRootWsActionTest { @Test public void execute_has_no_effect_when_user_is_already_not_root() { - UserDto otherUser = UserTesting.newUserDto(); - userDao.insert(dbSession, otherUser); - userDao.setRoot(dbSession, otherUser.getLogin(), true); - userDao.insert(dbSession, UserTesting.newUserDto(SOME_LOGIN, "name", "email")); - userDao.setRoot(dbSession, SOME_LOGIN, true); - dbSession.commit(); - userSessionRule.login().setRoot(); + UserDto otherUser = insertRootUser(newUserDto()); + insertNonRootUser(newUserDto(SOME_LOGIN, "name", "email")); + makeAuthenticatedUserRoot(); executeRequest(SOME_LOGIN); @@ -134,6 +127,47 @@ public class UnsetRootWsActionTest { assertThat(userDao.selectByLogin(dbSession, otherUser.getLogin()).isRoot()).isTrue(); } + @Test + public void execute_fails_with_BadRequestException_when_attempting_to_unset_root_on_last_root_user() { + insertRootUser(newUserDto(SOME_LOGIN, "name", "email")); + insertNonRootUser(newUserDto()); + makeAuthenticatedUserRoot(); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Last root can't be unset"); + + executeRequest(SOME_LOGIN); + } + + @Test + public void execute_fails_with_BadRequestException_when_attempting_to_unset_non_root_and_there_is_no_root_at_all() { + insertNonRootUser(newUserDto(SOME_LOGIN, "name", "email")); + insertNonRootUser(newUserDto()); + makeAuthenticatedUserRoot(); + + expectedException.expect(BadRequestException.class); + expectedException.expectMessage("Last root can't be unset"); + + executeRequest("non_existing_user"); + } + + private UserDto insertNonRootUser(UserDto dto) { + userDao.insert(dbSession, dto); + dbSession.commit(); + return dto; + } + + private UserDto insertRootUser(UserDto dto) { + insertNonRootUser(dto); + userDao.setRoot(dbSession, dto.getLogin(), true); + dbSession.commit(); + return dto; + } + + private void makeAuthenticatedUserRoot() { + userSessionRule.login().setRoot(); + } + private void expectInsufficientPrivilegesForbiddenException() { expectedException.expect(ForbiddenException.class); expectedException.expectMessage("Insufficient privileges"); @@ -145,8 +179,8 @@ public class UnsetRootWsActionTest { request.setParam("login", login); } return request - .execute() - .getStatus(); + .execute() + .getStatus(); } } diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserDao.java b/sonar-db/src/main/java/org/sonar/db/user/UserDao.java index f844726616a..5e1fe961e72 100644 --- a/sonar-db/src/main/java/org/sonar/db/user/UserDao.java +++ b/sonar-db/src/main/java/org/sonar/db/user/UserDao.java @@ -140,6 +140,10 @@ public class UserDao implements Dao { return mapper.selectUsers(query); } + public long countRootUsersButLogin(DbSession dbSession, String login) { + return getMapper(dbSession).countRootUsersButLogin(login); + } + public UserDto insert(DbSession session, UserDto dto) { getMapper(session).insert(dto); return dto; diff --git a/sonar-db/src/main/java/org/sonar/db/user/UserMapper.java b/sonar-db/src/main/java/org/sonar/db/user/UserMapper.java index b053b1f2e8b..517dc24d76d 100644 --- a/sonar-db/src/main/java/org/sonar/db/user/UserMapper.java +++ b/sonar-db/src/main/java/org/sonar/db/user/UserMapper.java @@ -53,6 +53,11 @@ public interface UserMapper { long countByEmail(String email); + /** + * Count actives users which are root and which login is not the specified one. + */ + long countRootUsersButLogin(@Param("login") String login); + void insert(UserDto userDto); void update(UserDto userDto); @@ -80,5 +85,4 @@ public interface UserMapper { void deletePropertiesMatchingLogin(@Param("propertyKeys") List<String> propertyKeys, @Param("login") String login); void deactivateUser(@Param("id") long userId, @Param("now") long now); - } diff --git a/sonar-db/src/main/resources/org/sonar/db/user/UserMapper.xml b/sonar-db/src/main/resources/org/sonar/db/user/UserMapper.xml index 66e370697b6..6de7be4b580 100644 --- a/sonar-db/src/main/resources/org/sonar/db/user/UserMapper.xml +++ b/sonar-db/src/main/resources/org/sonar/db/user/UserMapper.xml @@ -98,6 +98,17 @@ where lower(u.email)=#{email} AND u.active=${_true} </select> + <select id="countRootUsersButLogin" parameterType="String" resultType="long"> + select + count(1) + from + users u + where + u.active = ${_true} + and u.is_root = ${_true} + and u.login <> #{login} + </select> + <delete id="removeUserFromGroups" parameterType="long"> DELETE FROM groups_users WHERE user_id=#{id} </delete> diff --git a/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java b/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java index fd57b852a9c..dec3ce93999 100644 --- a/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java +++ b/sonar-db/src/test/java/org/sonar/db/user/UserDaoTest.java @@ -193,6 +193,101 @@ public class UserDaoTest { } @Test + public void countRootUsersButLogin_returns_0_when_there_is_no_user_at_all() { + assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); + } + + @Test + public void countRootUsersButLogin_returns_0_when_there_is_no_root() { + underTest.insert(session, newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); + } + + @Test + public void countRootUsersButLogin_returns_0_when_there_is_no_active_root() { + insertNonRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(0); + } + + @Test + public void countRootUsersButLogin_returns_count_of_all_active_roots_when_there_specified_login_does_not_exist() { + insertRootUser(newUserDto()); + insertNonRootUser(newUserDto()); + insertRootUser(newUserDto()); + insertRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, "bla")).isEqualTo(3); + } + + @Test + public void countRootUsersButLogin_returns_count_of_all_active_roots_when_specified_login_is_not_root() { + insertRootUser(newUserDto()); + String login = insertNonRootUser(newUserDto()).getLogin(); + insertRootUser(newUserDto()); + insertRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, login)).isEqualTo(3); + } + + @Test + public void countRootUsersButLogin_returns_count_of_all_active_roots_when_specified_login_is_inactive_root() { + insertRootUser(newUserDto()); + insertNonRootUser(newUserDto()); + insertRootUser(newUserDto()); + insertRootUser(newUserDto()); + String inactiveRootLogin = insertInactiveRootUser(newUserDto()).getLogin(); + insertInactiveRootUser(newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, inactiveRootLogin)).isEqualTo(3); + } + + @Test + public void countRootUsersButLogin_returns_count_of_all_active_roots_minus_one_when_specified_login_is_active_root() { + insertRootUser(newUserDto()); + insertNonRootUser(newUserDto()); + insertRootUser(newUserDto()); + String rootLogin = insertRootUser(newUserDto()).getLogin(); + insertInactiveRootUser(newUserDto()); + insertInactiveRootUser(newUserDto()); + session.commit(); + + assertThat(underTest.countRootUsersButLogin(session, rootLogin)).isEqualTo(2); + } + + private UserDto insertInactiveRootUser(UserDto dto) { + insertRootUser(dto); + dto.setActive(false); + underTest.update(session, dto); + session.commit(); + return dto; + } + + private UserDto insertRootUser(UserDto dto) { + underTest.insert(session, dto); + underTest.setRoot(session, dto.getLogin(), true); + session.commit(); + return dto; + } + + private UserDto insertNonRootUser(UserDto dto) { + underTest.insert(session, dto); + session.commit(); + return dto; + } + + @Test public void insert_user() { Long date = DateUtils.parseDate("2014-06-20").getTime(); |