diff options
author | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-11-25 09:41:19 +0100 |
---|---|---|
committer | Teryk Bellahsene <teryk.bellahsene@sonarsource.com> | 2015-11-26 14:12:36 +0100 |
commit | 93e81b2c3c3a4ebc644833cf4b364af800e808de (patch) | |
tree | 862b63f1d6c958636f4290e3fe77a9a23cd28a22 /server | |
parent | 1209d703eeae8130f87ebbe15306fd44e4675eb4 (diff) | |
download | sonarqube-93e81b2c3c3a4ebc644833cf4b364af800e808de.tar.gz sonarqube-93e81b2c3c3a4ebc644833cf4b364af800e808de.zip |
SONAR-7042 WS user_tokens/revoke revoke an access token
Diffstat (limited to 'server')
6 files changed, 228 insertions, 3 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usertoken/UserTokenModule.java b/server/sonar-server/src/main/java/org/sonar/server/usertoken/UserTokenModule.java index 2fd1753fe2c..5583e636ddd 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/usertoken/UserTokenModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/usertoken/UserTokenModule.java @@ -22,6 +22,7 @@ package org.sonar.server.usertoken; import org.sonar.core.platform.Module; import org.sonar.server.usertoken.ws.GenerateAction; +import org.sonar.server.usertoken.ws.RevokeAction; import org.sonar.server.usertoken.ws.UserTokensWs; public class UserTokenModule extends Module { @@ -30,6 +31,7 @@ public class UserTokenModule extends Module { add( UserTokensWs.class, GenerateAction.class, + RevokeAction.class, UserTokenAuthenticator.class, TokenGeneratorImpl.class); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/GenerateAction.java b/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/GenerateAction.java index 7ed59918eda..300f729faa2 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/GenerateAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/GenerateAction.java @@ -50,7 +50,7 @@ public class GenerateAction implements UserTokensWsAction { private final System2 system; private final TokenGenerator tokenGenerator; - public GenerateAction(UserSession userSession, DbClient dbClient, System2 system, TokenGenerator tokenGenerator) { + public GenerateAction(DbClient dbClient, UserSession userSession, System2 system, TokenGenerator tokenGenerator) { this.userSession = userSession; this.dbClient = dbClient; this.system = system; diff --git a/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/RevokeAction.java b/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/RevokeAction.java new file mode 100644 index 00000000000..32dece255cb --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/usertoken/ws/RevokeAction.java @@ -0,0 +1,88 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.usertoken.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.server.user.UserSession; +import org.sonarqube.ws.client.usertoken.RevokeWsRequest; + +import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN; +import static org.sonarqube.ws.client.usertoken.UserTokensWsParameters.ACTION_REVOKE; +import static org.sonarqube.ws.client.usertoken.UserTokensWsParameters.PARAM_LOGIN; +import static org.sonarqube.ws.client.usertoken.UserTokensWsParameters.PARAM_NAME; + +public class RevokeAction implements UserTokensWsAction { + private final DbClient dbClient; + private final UserSession userSession; + + public RevokeAction(DbClient dbClient, UserSession userSession) { + this.dbClient = dbClient; + this.userSession = userSession; + } + + @Override + public void define(WebService.NewController context) { + WebService.NewAction action = context.createAction(ACTION_REVOKE) + .setDescription("Revoke a user access token. <br/>"+ + "It requires administration permissions.") + .setSince("5.3") + .setPost(true) + .setHandler(this); + + action.createParam(PARAM_LOGIN) + .setRequired(true) + .setDescription("User login") + .setExampleValue("g.hopper"); + + action.createParam(PARAM_NAME) + .setRequired(true) + .setDescription("Token name") + .setExampleValue("Project scan on Travis"); + } + + @Override + public void handle(Request request, Response response) throws Exception { + doHandle(toRevokeWsRequest(request)); + response.noContent(); + } + + private void doHandle(RevokeWsRequest request) { + userSession.checkLoggedIn().checkGlobalPermission(SYSTEM_ADMIN); + + DbSession dbSession = dbClient.openSession(false); + try { + dbClient.userTokenDao().deleteByLoginAndName(dbSession, request.getLogin(), request.getName()); + dbSession.commit(); + } finally { + dbClient.closeSession(dbSession); + } + } + + private static RevokeWsRequest toRevokeWsRequest(Request request) { + return new RevokeWsRequest() + .setLogin(request.mandatoryParam(PARAM_LOGIN)) + .setName(request.mandatoryParam(PARAM_NAME)); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/GenerateActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/GenerateActionTest.java index a4190e479ef..e0b0e11ca9b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/GenerateActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/GenerateActionTest.java @@ -79,7 +79,7 @@ public class GenerateActionTest { userDb.insertUser(newUserDto().setLogin(ADA_LOVELACE)); ws = new WsActionTester( - new GenerateAction(userSession, db.getDbClient(), System2.INSTANCE, tokenGenerator)); + new GenerateAction(db.getDbClient(), userSession, System2.INSTANCE, tokenGenerator)); } @Test diff --git a/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/RevokeActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/RevokeActionTest.java new file mode 100644 index 00000000000..e9e0995338c --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/RevokeActionTest.java @@ -0,0 +1,123 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube 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. + * + * SonarQube 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.usertoken.ws; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.core.permission.GlobalPermissions; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.user.UserTokenDto; +import org.sonar.server.exceptions.ForbiddenException; +import org.sonar.server.exceptions.UnauthorizedException; +import org.sonar.server.tester.UserSessionRule; +import org.sonar.server.ws.WsActionTester; +import org.sonar.test.DbTests; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.db.user.UserTokenTesting.newUserToken; +import static org.sonarqube.ws.client.usertoken.UserTokensWsParameters.PARAM_LOGIN; +import static org.sonarqube.ws.client.usertoken.UserTokensWsParameters.PARAM_NAME; + +@Category(DbTests.class) +public class RevokeActionTest { + static final String GRACE_HOPPER = "grace.hopper"; + static final String ADA_LOVELACE = "ada.lovelace"; + static final String TOKEN_NAME = "token-name"; + + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + DbClient dbClient = db.getDbClient(); + DbSession dbSession = db.getSession(); + @Rule + public UserSessionRule userSession = UserSessionRule.standalone(); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + WsActionTester ws; + + @Before + public void setUp() { + userSession + .login() + .setGlobalPermissions(GlobalPermissions.SYSTEM_ADMIN); + + ws = new WsActionTester( + new RevokeAction(dbClient, userSession)); + } + + @Test + public void delete_token_in_db() { + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-delete")); + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-keep-1")); + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName("token-to-keep-2")); + insertUserToken(newUserToken().setLogin(ADA_LOVELACE).setName("token-to-delete")); + + String response = newRequest(GRACE_HOPPER, "token-to-delete"); + + assertThat(response).isEmpty(); + assertThat(dbClient.userTokenDao().selectByLogin(dbSession, GRACE_HOPPER)).extracting("name").containsOnly("token-to-keep-1", "token-to-keep-2"); + assertThat(dbClient.userTokenDao().selectByLogin(dbSession, ADA_LOVELACE)).extracting("name").containsOnly("token-to-delete"); + } + + @Test + public void does_not_fail_when_incorrect_login_or_name() { + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME)); + + newRequest(ADA_LOVELACE, "another-token-name"); + } + + @Test + public void fail_if_not_logged_in() { + userSession.anonymous(); + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME)); + expectedException.expect(UnauthorizedException.class); + + newRequest(GRACE_HOPPER, TOKEN_NAME); + } + + @Test + public void fail_if_insufficient_privileges() { + userSession.login().setGlobalPermissions(GlobalPermissions.SCAN_EXECUTION); + insertUserToken(newUserToken().setLogin(GRACE_HOPPER).setName(TOKEN_NAME)); + expectedException.expect(ForbiddenException.class); + + newRequest(GRACE_HOPPER, TOKEN_NAME); + } + + private String newRequest(String login, String name) { + return ws.newRequest() + .setParam(PARAM_LOGIN, login) + .setParam(PARAM_NAME, name) + .execute().getInput(); + } + + private void insertUserToken(UserTokenDto userToken) { + dbClient.userTokenDao().insert(dbSession, userToken); + dbSession.commit(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/UserTokensWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/UserTokensWsTest.java index 4f3ad84603e..b4b3b561762 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/UserTokensWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/usertoken/ws/UserTokensWsTest.java @@ -45,7 +45,8 @@ public class UserTokensWsTest { TokenGenerator tokenGenerator = mock(TokenGenerator.class); ws = new WsTester(new UserTokensWs( - new GenerateAction(userSession, dbClient, system, tokenGenerator))); + new GenerateAction(dbClient, userSession, system, tokenGenerator), + new RevokeAction(dbClient, userSession))); } @Test @@ -59,4 +60,15 @@ public class UserTokensWsTest { assertThat(action.param("login").isRequired()).isTrue(); assertThat(action.param("name").isRequired()).isTrue(); } + + @Test + public void revoke_action() { + WebService.Action action = ws.action(CONTROLLER_KEY, "revoke"); + + assertThat(action).isNotNull(); + assertThat(action.since()).isEqualTo("5.3"); + assertThat(action.isPost()).isTrue(); + assertThat(action.param("login").isRequired()).isTrue(); + assertThat(action.param("name").isRequired()).isTrue(); + } } |