aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2016-11-30 17:46:08 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2016-12-05 10:07:12 +0100
commitb8bb296917cace6ec2ae8ad5763ff132d0f6daa2 (patch)
tree42c6396d0955b479caa9eaec22686ff5a0b3e03b
parentd753886eb88d763b78c7431746d8c91e89937070 (diff)
downloadsonarqube-b8bb296917cace6ec2ae8ad5763ff132d0f6daa2.tar.gz
sonarqube-b8bb296917cace6ec2ae8ad5763ff132d0f6daa2.zip
SONAR-7774 Create /api/authentication/logout WS
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/ws/AuthenticationWs.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LoginAction.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LogoutAction.java73
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticationModuleTest.java37
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java1
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/authentication/ws/LogoutActionTest.java84
10 files changed, 220 insertions, 8 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java
index 639a9db840e..cbc0ce0fab8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/AuthenticationModule.java
@@ -23,6 +23,7 @@ import org.sonar.core.platform.Module;
import org.sonar.server.authentication.event.AuthenticationEventImpl;
import org.sonar.server.authentication.ws.AuthenticationWs;
import org.sonar.server.authentication.ws.LoginAction;
+import org.sonar.server.authentication.ws.LogoutAction;
import org.sonar.server.authentication.ws.ValidateAction;
public class AuthenticationModule extends Module {
@@ -43,6 +44,7 @@ public class AuthenticationModule extends Module {
JwtHttpHandler.class,
JwtCsrfVerifier.class,
LoginAction.class,
+ LogoutAction.class,
CredentialsAuthenticator.class,
RealmAuthenticator.class,
BasicAuthenticator.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java
index baa29d745ff..391897dde77 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java
@@ -161,7 +161,7 @@ public class JwtHttpHandler {
jwtCsrfVerifier.refreshState(request, response, (String) token.get(CSRF_JWT_PARAM), sessionTimeoutInSeconds);
}
- void removeToken(HttpServletRequest request, HttpServletResponse response) {
+ public void removeToken(HttpServletRequest request, HttpServletResponse response) {
response.addCookie(createCookie(request, JWT_COOKIE, null, 0));
jwtCsrfVerifier.removeState(request, response);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
index f63d4efd7d8..a466d6f5656 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/UserSessionInitializer.java
@@ -42,6 +42,7 @@ import static org.sonar.server.authentication.AuthenticationError.handleAuthenti
import static org.sonar.server.authentication.event.AuthenticationEvent.Method;
import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
import static org.sonar.server.authentication.ws.LoginAction.AUTH_LOGIN_URL;
+import static org.sonar.server.authentication.ws.LogoutAction.AUTH_LOGOUT_URL;
import static org.sonar.server.authentication.ws.ValidateAction.AUTH_VALIDATE_URL;
import static org.sonar.server.user.ServerUserSession.createForAnonymous;
import static org.sonar.server.user.ServerUserSession.createForUser;
@@ -64,7 +65,7 @@ public class UserSessionInitializer {
"/sessions/*",
"/api/system/db_migration_status", "/api/system/status", "/api/system/migrate_db",
"/api/server/index", "/api/server/setup", "/api/server/version",
- AUTH_LOGIN_URL, AUTH_VALIDATE_URL);
+ AUTH_LOGIN_URL, AUTH_VALIDATE_URL, AUTH_LOGOUT_URL);
private static final UrlPattern URL_PATTERN = UrlPattern.builder()
.includes("/*")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/AuthenticationWs.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/AuthenticationWs.java
index e55a96f5dc7..f17864b081e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/AuthenticationWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/AuthenticationWs.java
@@ -32,6 +32,7 @@ public class AuthenticationWs implements WebService {
controller.setDescription("Handle authentication.");
defineLoginAction(controller);
+ defineLogoutAction(controller);
defineValidateAction(controller);
controller.done();
@@ -61,4 +62,12 @@ public class AuthenticationWs implements WebService {
.setRequired(true);
}
+ private static void defineLogoutAction(NewController controller) {
+ controller.createAction("logout")
+ .setDescription("Logout a user.")
+ .setSince("6.3")
+ .setPost(true)
+ .setHandler(ServletFilterHandler.INSTANCE);
+ }
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LoginAction.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LoginAction.java
index c7afb3f134c..e0e0dff34fd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LoginAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LoginAction.java
@@ -45,13 +45,12 @@ import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
import static org.apache.commons.lang.StringUtils.isEmpty;
import static org.sonar.server.authentication.event.AuthenticationEvent.Method;
import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
+import static org.sonarqube.ws.client.WsRequest.Method.POST;
public class LoginAction extends ServletFilter {
public static final String AUTH_LOGIN_URL = "/api/authentication/login";
- private static final String POST = "POST";
-
private final DbClient dbClient;
private final CredentialsAuthenticator credentialsAuthenticator;
private final JwtHttpHandler jwtHttpHandler;
@@ -77,7 +76,7 @@ public class LoginAction extends ServletFilter {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
- if (!request.getMethod().equals(POST)) {
+ if (!request.getMethod().equals(POST.name())) {
response.setStatus(HTTP_BAD_REQUEST);
return;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LogoutAction.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LogoutAction.java
new file mode 100644
index 00000000000..b951204ab7e
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LogoutAction.java
@@ -0,0 +1,73 @@
+/*
+ * 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.authentication.ws;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.sonar.api.web.ServletFilter;
+import org.sonar.server.authentication.JwtHttpHandler;
+
+import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
+import static org.sonarqube.ws.client.WsRequest.Method.POST;
+
+public class LogoutAction extends ServletFilter {
+
+ public static final String AUTH_LOGOUT_URL = "/api/authentication/logout";
+
+ private final JwtHttpHandler jwtHttpHandler;
+
+ public LogoutAction(JwtHttpHandler jwtHttpHandler) {
+ this.jwtHttpHandler = jwtHttpHandler;
+ }
+
+ @Override
+ public UrlPattern doGetPattern() {
+ return UrlPattern.create(AUTH_LOGOUT_URL);
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
+ HttpServletRequest request = (HttpServletRequest) servletRequest;
+ HttpServletResponse response = (HttpServletResponse) servletResponse;
+
+ if (!request.getMethod().equals(POST.name())) {
+ response.setStatus(HTTP_BAD_REQUEST);
+ return;
+ }
+ jwtHttpHandler.removeToken(request, response);
+ }
+
+ @Override
+ public void init(FilterConfig filterConfig) throws ServletException {
+ // Nothing to do
+ }
+
+ @Override
+ public void destroy() {
+ // Nothing to do
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticationModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticationModuleTest.java
new file mode 100644
index 00000000000..ca37d899066
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/AuthenticationModuleTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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.authentication;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class AuthenticationModuleTest {
+
+ @Test
+ public void verify_count_of_added_components() {
+ ComponentContainer container = new ComponentContainer();
+ new AuthenticationModule().configure(container);
+ assertThat(container.size()).isEqualTo(2 + 20);
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java
index b57103037e9..8c08aad4059 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/UserSessionInitializerTest.java
@@ -96,6 +96,7 @@ public class UserSessionInitializerTest {
assertPathIsNotIgnored("/api/server_id/show");
assertPathIsIgnored("/api/authentication/login");
+ assertPathIsIgnored("/api/authentication/logout");
assertPathIsIgnored("/api/authentication/validate");
assertPathIsIgnored("/batch/index");
assertPathIsIgnored("/batch/file");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsTest.java
index 6fabde5e670..980e4a2e433 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/AuthenticationWsTest.java
@@ -19,13 +19,13 @@
*/
package org.sonar.server.authentication.ws;
-import static org.assertj.core.api.Assertions.assertThat;
-
import org.junit.Test;
import org.sonar.api.server.ws.WebService;
import org.sonar.server.ws.ServletFilterHandler;
import org.sonar.server.ws.WsTester;
+import static org.assertj.core.api.Assertions.assertThat;
+
public class AuthenticationWsTest {
WsTester tester = new WsTester(new AuthenticationWs());
@@ -35,7 +35,7 @@ public class AuthenticationWsTest {
WebService.Controller controller = tester.controller("api/authentication");
assertThat(controller).isNotNull();
assertThat(controller.description()).isNotEmpty();
- assertThat(controller.actions()).hasSize(2);
+ assertThat(controller.actions()).hasSize(3);
WebService.Action validate = controller.action("validate");
assertThat(validate).isNotNull();
@@ -48,5 +48,11 @@ public class AuthenticationWsTest {
assertThat(login.handler()).isInstanceOf(ServletFilterHandler.class);
assertThat(login.isPost()).isTrue();
assertThat(login.params()).hasSize(2);
+
+ WebService.Action logout = controller.action("logout");
+ assertThat(logout).isNotNull();
+ assertThat(logout.handler()).isInstanceOf(ServletFilterHandler.class);
+ assertThat(logout.isPost()).isTrue();
+ assertThat(logout.params()).isEmpty();
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/LogoutActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/LogoutActionTest.java
new file mode 100644
index 00000000000..fad0f70d92c
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/authentication/ws/LogoutActionTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.authentication.ws;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.server.authentication.JwtHttpHandler;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class LogoutActionTest {
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
+ FilterChain chain = mock(FilterChain.class);
+
+ JwtHttpHandler jwtHttpHandler = mock(JwtHttpHandler.class);
+
+ LogoutAction underTest = new LogoutAction(jwtHttpHandler);
+
+ @Test
+ public void do_get_pattern() throws Exception {
+ assertThat(underTest.doGetPattern().matches("/api/authentication/logout")).isTrue();
+ assertThat(underTest.doGetPattern().matches("/api/authentication/login")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/api/authentication/logou")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/api/authentication/logoutthing")).isFalse();
+ assertThat(underTest.doGetPattern().matches("/foo")).isFalse();
+ }
+
+ @Test
+ public void return_400_on_get_request() throws Exception {
+ when(request.getMethod()).thenReturn("GET");
+
+ underTest.doFilter(request, response, chain);
+
+ verifyZeroInteractions(jwtHttpHandler, chain);
+ verify(response).setStatus(400);
+ }
+
+ @Test
+ public void logout() throws Exception {
+ executeRequest();
+
+ verify(jwtHttpHandler).removeToken(request, response);
+ verifyZeroInteractions(chain);
+ }
+
+ private void executeRequest() throws IOException, ServletException {
+ when(request.getMethod()).thenReturn("POST");
+ underTest.doFilter(request, response, chain);
+ }
+}