@@ -197,6 +197,7 @@ import org.sonar.server.qualityprofile.ws.OldRestoreAction; | |||
import org.sonar.server.qualityprofile.ws.ProfilesWs; | |||
import org.sonar.server.qualityprofile.ws.QProfilesWsModule; | |||
import org.sonar.server.qualityprofile.ws.SearchDataLoader; | |||
import org.sonar.server.root.ws.RootWsModule; | |||
import org.sonar.server.rule.CommonRuleDefinitionsImpl; | |||
import org.sonar.server.rule.DefaultRuleFinder; | |||
import org.sonar.server.rule.DeprecatedRulesDefinitionLoader; | |||
@@ -404,7 +405,6 @@ public class PlatformLevel4 extends PlatformLevel { | |||
WebServiceFilter.class, | |||
// localization | |||
L10nWs.class, | |||
// authentication | |||
@@ -598,7 +598,10 @@ public class PlatformLevel4 extends PlatformLevel { | |||
GlobalNavigationAction.class, | |||
SettingsNavigationAction.class, | |||
ComponentNavigationAction.class, | |||
NavigationWs.class); | |||
NavigationWs.class, | |||
// root | |||
RootWsModule.class); | |||
addAll(level4AddedComponents); | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import org.sonar.api.server.ws.WebService; | |||
public class RootWs implements WebService { | |||
private final RootWsAction[] actions; | |||
public RootWs(RootWsAction... actions) { | |||
this.actions = actions; | |||
} | |||
@Override | |||
public void define(Context context) { | |||
NewController controller = context.createController("api/root") | |||
.setSince("6.2") | |||
.setDescription("Manage root users"); | |||
for (RootWsAction action : actions) { | |||
action.define(controller); | |||
} | |||
controller.done(); | |||
} | |||
} |
@@ -0,0 +1,26 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import org.sonar.server.ws.WsAction; | |||
public interface RootWsAction extends WsAction { | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import org.sonar.core.platform.Module; | |||
public class RootWsModule extends Module { | |||
@Override | |||
protected void configureModule() { | |||
add(RootWs.class, | |||
SetRootWsAction.class); | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import org.sonar.api.server.ws.Request; | |||
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.db.user.UserDto; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
import org.sonar.server.user.UserSession; | |||
import static java.lang.String.format; | |||
public class SetRootWsAction implements RootWsAction { | |||
private static final String PARAM_LOGIN = "login"; | |||
private final UserSession userSession; | |||
private final DbClient dbClient; | |||
public SetRootWsAction(UserSession userSession, DbClient dbClient) { | |||
this.userSession = userSession; | |||
this.dbClient = dbClient; | |||
} | |||
@Override | |||
public void define(WebService.NewController controller) { | |||
WebService.NewAction action = controller.createAction("set_root") | |||
.setInternal(true) | |||
.setPost(true) | |||
.setDescription("Make the specified user root.<br/>" + | |||
"Requires to be root.") | |||
.setSince("6.2") | |||
.setHandler(this); | |||
action.createParam(PARAM_LOGIN) | |||
.setDescription("A user login") | |||
.setExampleValue("admin") | |||
.setRequired(true) | |||
.setSince("6.2"); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
userSession.checkIsRoot(); | |||
String login = request.mandatoryParam(PARAM_LOGIN); | |||
try (DbSession dbSession = dbClient.openSession(false)) { | |||
UserDto userDto = dbClient.userDao().selectByLogin(dbSession, login); | |||
if (userDto == null || !userDto.isActive()) { | |||
throw new NotFoundException(format("User with login '%s' not found", login)); | |||
} | |||
if (!userDto.isRoot()) { | |||
dbClient.userDao().setRoot(dbSession, login, true); | |||
dbSession.commit(); | |||
} | |||
} | |||
response.noContent(); | |||
} | |||
} |
@@ -0,0 +1,23 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.server.root.ws; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -0,0 +1,53 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import org.junit.Test; | |||
import org.sonar.api.server.ws.Request; | |||
import org.sonar.api.server.ws.Response; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.server.ws.WsTester; | |||
import static org.assertj.core.api.Assertions.assertThat; | |||
public class RootWsTest { | |||
private RootWs underTest = new RootWs(new DummyRootWsAction()); | |||
private WsTester wsTester = new WsTester(underTest); | |||
@Test | |||
public void verify_definition() { | |||
assertThat(wsTester.context().controllers()).hasSize(1); | |||
WebService.Controller controller = wsTester.context().controller("api/root"); | |||
assertThat(controller.description()).isEqualTo("Manage root users"); | |||
assertThat(controller.since()).isEqualTo("6.2"); | |||
} | |||
private static class DummyRootWsAction implements RootWsAction { | |||
@Override | |||
public void define(WebService.NewController context) { | |||
context.createAction("ooo").setHandler(this); | |||
} | |||
@Override | |||
public void handle(Request request, Response response) throws Exception { | |||
} | |||
} | |||
} |
@@ -0,0 +1,176 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2016 SonarSource SA | |||
* mailto:contact AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
package org.sonar.server.root.ws; | |||
import javax.annotation.Nullable; | |||
import org.junit.Rule; | |||
import org.junit.Test; | |||
import org.junit.rules.ExpectedException; | |||
import org.sonar.api.server.ws.WebService; | |||
import org.sonar.api.utils.System2; | |||
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.ForbiddenException; | |||
import org.sonar.server.exceptions.NotFoundException; | |||
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; | |||
public class SetRootWsActionTest { | |||
private static final String SOME_LOGIN = "johndoe"; | |||
@Rule | |||
public DbTester dbTester = DbTester.create(System2.INSTANCE); | |||
@Rule | |||
public UserSessionRule userSessionRule = UserSessionRule.standalone(); | |||
@Rule | |||
public ExpectedException expectedException = ExpectedException.none(); | |||
private UserDao userDao = dbTester.getDbClient().userDao(); | |||
private DbSession dbSession = dbTester.getSession(); | |||
private SetRootWsAction underTest = new SetRootWsAction(userSessionRule, dbTester.getDbClient()); | |||
private WsActionTester wsTester = new WsActionTester(underTest); | |||
@Test | |||
public void verify_definition() { | |||
WebService.Action action = wsTester.getDef(); | |||
assertThat(action.key()).isEqualTo("set_root"); | |||
assertThat(action.isInternal()).isTrue(); | |||
assertThat(action.isPost()).isTrue(); | |||
assertThat(action.since()).isEqualTo("6.2"); | |||
assertThat(action.description()).isEqualTo("Make the specified user root.<br/>" + | |||
"Requires to be root."); | |||
assertThat(action.responseExample()).isNull(); | |||
assertThat(action.deprecatedKey()).isNull(); | |||
assertThat(action.deprecatedSince()).isNull(); | |||
assertThat(action.handler()).isSameAs(underTest); | |||
assertThat(action.params()).hasSize(1); | |||
WebService.Param param = action.param("login"); | |||
assertThat(param.isRequired()).isTrue(); | |||
assertThat(param.description()).isEqualTo("A user login"); | |||
assertThat(param.defaultValue()).isNull(); | |||
assertThat(param.deprecatedSince()).isNull(); | |||
assertThat(param.deprecatedKey()).isNull(); | |||
assertThat(param.exampleValue()).isEqualTo("admin"); | |||
} | |||
@Test | |||
public void execute_fails_with_ForbiddenException_when_user_is_not_logged_in() { | |||
expectInsufficientPrivilegesForbiddenException(); | |||
executeRequest(SOME_LOGIN); | |||
} | |||
@Test | |||
public void execute_fails_with_ForbiddenException_when_user_is_not_root() { | |||
userSessionRule.login(); | |||
expectInsufficientPrivilegesForbiddenException(); | |||
executeRequest(SOME_LOGIN); | |||
} | |||
@Test | |||
public void execute_fails_with_IAE_when_login_param_is_not_provided() { | |||
makeAuthenticatedUserRoot(); | |||
expectedException.expect(IllegalArgumentException.class); | |||
expectedException.expectMessage("The 'login' parameter is missing"); | |||
executeRequest(null); | |||
} | |||
@Test | |||
public void execute_makes_user_with_specified_login_root_when_it_is_not() { | |||
UserDto otherUser = UserTesting.newUserDto(); | |||
userDao.insert(dbSession, otherUser); | |||
userDao.insert(dbSession, UserTesting.newUserDto(SOME_LOGIN, "name", "email")); | |||
dbSession.commit(); | |||
makeAuthenticatedUserRoot(); | |||
executeRequest(SOME_LOGIN); | |||
assertThat(userDao.selectByLogin(dbSession, SOME_LOGIN).isRoot()).isTrue(); | |||
assertThat(userDao.selectByLogin(dbSession, otherUser.getLogin()).isRoot()).isFalse(); | |||
} | |||
@Test | |||
public void execute_has_no_effect_when_user_is_already_root() { | |||
UserDto otherUser = UserTesting.newUserDto(); | |||
userDao.insert(dbSession, otherUser); | |||
userDao.insert(dbSession, UserTesting.newUserDto(SOME_LOGIN, "name", "email")); | |||
userDao.setRoot(dbSession, SOME_LOGIN, true); | |||
dbSession.commit(); | |||
makeAuthenticatedUserRoot(); | |||
executeRequest(SOME_LOGIN); | |||
assertThat(userDao.selectByLogin(dbSession, SOME_LOGIN).isRoot()).isTrue(); | |||
assertThat(userDao.selectByLogin(dbSession, otherUser.getLogin()).isRoot()).isFalse(); | |||
} | |||
@Test | |||
public void execute_fails_with_NotFoundException_when_user_for_specified_login_does_not_exist() { | |||
makeAuthenticatedUserRoot(); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User with login 'foo_bar' not found"); | |||
executeRequest("foo_bar"); | |||
} | |||
@Test | |||
public void execute_fails_with_NotFoundException_when_user_for_specified_login_is_not_active() { | |||
UserDto userDto = UserTesting.newUserDto().setActive(false); | |||
userDao.insert(dbSession, userDto); | |||
dbSession.commit(); | |||
makeAuthenticatedUserRoot(); | |||
expectedException.expect(NotFoundException.class); | |||
expectedException.expectMessage("User with login '" + userDto.getLogin() + "' not found"); | |||
executeRequest(userDto.getLogin()); | |||
} | |||
private void makeAuthenticatedUserRoot() { | |||
userSessionRule.login().setRoot(); | |||
} | |||
private void expectInsufficientPrivilegesForbiddenException() { | |||
expectedException.expect(ForbiddenException.class); | |||
expectedException.expectMessage("Insufficient privileges"); | |||
} | |||
private int executeRequest(@Nullable String login) { | |||
TestRequest request = wsTester.newRequest(); | |||
if (login != null) { | |||
request.setParam("login", login); | |||
} | |||
return request | |||
.execute() | |||
.getStatus(); | |||
} | |||
} |