]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-8684 Always create cookie with web context 1568/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 26 Jan 2017 07:50:24 +0000 (08:50 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 26 Jan 2017 16:54:19 +0000 (17:54 +0100)
server/sonar-server/src/main/java/org/sonar/server/authentication/CookieUtils.java [deleted file]
server/sonar-server/src/main/java/org/sonar/server/authentication/Cookies.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/authentication/JwtCsrfVerifier.java
server/sonar-server/src/main/java/org/sonar/server/authentication/JwtHttpHandler.java
server/sonar-server/src/main/java/org/sonar/server/authentication/OAuthCsrfVerifier.java
server/sonar-server/src/main/java/org/sonar/server/authentication/ws/LogoutAction.java
server/sonar-server/src/test/java/org/sonar/server/authentication/CookieUtilsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/authentication/CookiesTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/authentication/ws/LogoutActionTest.java

diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/CookieUtils.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/CookieUtils.java
deleted file mode 100644 (file)
index 02baa1c..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 java.util.Arrays;
-import java.util.Optional;
-import javax.annotation.Nullable;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-
-public class CookieUtils {
-
-  private static final String HTTPS_HEADER = "X-Forwarded-Proto";
-  private static final String HTTPS_VALUE = "https";
-
-  private CookieUtils() {
-    // Only static methods
-  }
-
-  public static Optional<Cookie> findCookie(String cookieName, HttpServletRequest request) {
-    Cookie[] cookies = request.getCookies();
-    if (cookies == null) {
-      return Optional.empty();
-    }
-    return Arrays.stream(cookies)
-      .filter(cookie -> cookieName.equals(cookie.getName()))
-      .findFirst();
-  }
-
-  public static Cookie createCookie(String name, @Nullable String value, boolean httpOnly, int expiry, HttpServletRequest request) {
-    Cookie cookie = new Cookie(name, value);
-    // Path is set "/" in order to allow rails to be able to remove cookies
-    // TODO When logout when be implemented in Java (SONAR-7774), following line should be replaced by
-    // cookie.setPath(request.getContextPath()"/");
-    cookie.setPath("/");
-    cookie.setSecure(isHttps(request));
-    cookie.setHttpOnly(httpOnly);
-    cookie.setMaxAge(expiry);
-    return cookie;
-  }
-
-  private static boolean isHttps(HttpServletRequest request) {
-    return HTTPS_VALUE.equalsIgnoreCase(request.getHeader(HTTPS_HEADER));
-  }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/authentication/Cookies.java b/server/sonar-server/src/main/java/org/sonar/server/authentication/Cookies.java
new file mode 100644 (file)
index 0000000..c1cd587
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Optional;
+import javax.annotation.Nullable;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.util.Objects.requireNonNull;
+
+public class Cookies {
+
+  private static final String HTTPS_HEADER = "X-Forwarded-Proto";
+  private static final String HTTPS_VALUE = "https";
+
+  private Cookies() {
+    // Only static methods
+  }
+
+  public static Optional<Cookie> findCookie(String cookieName, HttpServletRequest request) {
+    Cookie[] cookies = request.getCookies();
+    if (cookies == null) {
+      return Optional.empty();
+    }
+    return Arrays.stream(cookies)
+      .filter(cookie -> cookieName.equals(cookie.getName()))
+      .findFirst();
+  }
+
+  public static CookieBuilder newCookieBuilder(HttpServletRequest request) {
+    return new CookieBuilder(request);
+  }
+
+  public static class CookieBuilder {
+
+    private final HttpServletRequest request;
+
+    private String name;
+    private String value;
+    private boolean httpOnly;
+    private int expiry;
+
+    public CookieBuilder(HttpServletRequest request) {
+      this.request = request;
+    }
+
+    public CookieBuilder setName(String name) {
+      this.name = requireNonNull(name);
+      return this;
+    }
+
+    public CookieBuilder setValue(@Nullable String value) {
+      this.value = value;
+      return this;
+    }
+
+    public CookieBuilder setHttpOnly(boolean httpOnly) {
+      this.httpOnly = httpOnly;
+      return this;
+    }
+
+    public CookieBuilder setExpiry(int expiry) {
+      this.expiry = expiry;
+      return this;
+    }
+
+    public Cookie build() {
+      Cookie cookie = new Cookie(requireNonNull(name), value);
+      cookie.setPath(getContextPath(request));
+      cookie.setSecure(isHttps(request));
+      cookie.setHttpOnly(httpOnly);
+      cookie.setMaxAge(expiry);
+      return cookie;
+    }
+
+    private static boolean isHttps(HttpServletRequest request) {
+      return HTTPS_VALUE.equalsIgnoreCase(request.getHeader(HTTPS_HEADER));
+    }
+
+    private static String getContextPath(HttpServletRequest request) {
+      String path = request.getContextPath();
+      return isNullOrEmpty(path) ? "/" : path;
+    }
+  }
+}
index 4a156d9799e1fdfd565feebafe2583986eb54cf6..28ada037e160be0a29274d9cc9703bb8c259d68b 100644 (file)
@@ -31,7 +31,7 @@ import org.apache.commons.lang.StringUtils;
 import org.sonar.server.authentication.event.AuthenticationException;
 
 import static org.apache.commons.lang.StringUtils.isBlank;
-import static org.sonar.server.authentication.CookieUtils.createCookie;
+import static org.sonar.server.authentication.Cookies.newCookieBuilder;
 import static org.sonar.server.authentication.event.AuthenticationEvent.Method;
 import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
 
@@ -48,7 +48,7 @@ public class JwtCsrfVerifier {
     // Create a state token to prevent request forgery.
     // Store it in the cookie for later validation.
     String state = new BigInteger(130, new SecureRandom()).toString(32);
-    response.addCookie(createCookie(CSRF_STATE_COOKIE, state, false, timeoutInSeconds, request));
+    response.addCookie(newCookieBuilder(request).setName(CSRF_STATE_COOKIE).setValue(state).setHttpOnly(false).setExpiry(timeoutInSeconds).build());
     return state;
   }
 
@@ -79,11 +79,11 @@ public class JwtCsrfVerifier {
   }
 
   public void refreshState(HttpServletRequest request, HttpServletResponse response, String csrfState, int timeoutInSeconds) {
-    response.addCookie(createCookie(CSRF_STATE_COOKIE, csrfState, false, timeoutInSeconds, request));
+    response.addCookie(newCookieBuilder(request).setName(CSRF_STATE_COOKIE).setValue(csrfState).setHttpOnly(false).setExpiry(timeoutInSeconds).build());
   }
 
   public void removeState(HttpServletRequest request, HttpServletResponse response) {
-    response.addCookie(createCookie(CSRF_STATE_COOKIE, null, false, 0, request));
+    response.addCookie(newCookieBuilder(request).setName(CSRF_STATE_COOKIE).setValue(null).setHttpOnly(false).setExpiry(0).build());
   }
 
   private static boolean shouldRequestBeChecked(HttpServletRequest request) {
index 5b9eb6fabe39b21f882c5787f5a4d48dc6e8f4b8..cd01aa1d02162b49913a297997e6c277be39df1a 100644 (file)
@@ -41,7 +41,8 @@ import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.Objects.requireNonNull;
 import static org.apache.commons.lang.StringUtils.isEmpty;
 import static org.apache.commons.lang.time.DateUtils.addSeconds;
-import static org.sonar.server.authentication.CookieUtils.findCookie;
+import static org.sonar.server.authentication.Cookies.findCookie;
+import static org.sonar.server.authentication.Cookies.newCookieBuilder;
 
 @ServerSide
 public class JwtHttpHandler {
@@ -167,7 +168,7 @@ public class JwtHttpHandler {
   }
 
   private static Cookie createCookie(HttpServletRequest request, String name, @Nullable String value, int expirationInSeconds) {
-    return CookieUtils.createCookie(name, value, true, expirationInSeconds, request);
+    return newCookieBuilder(request).setName(name).setValue(value).setHttpOnly(true).setExpiry(expirationInSeconds).build();
   }
 
   private Optional<UserDto> selectUserFromDb(String userLogin) {
index 2c29f2c1a093cf19e82f7292baa9726bfd0ed3bb..e75171eeb510c814f977bf49e10bed56feca05c8 100644 (file)
@@ -30,8 +30,8 @@ import org.sonar.server.authentication.event.AuthenticationException;
 import static java.lang.String.format;
 import static org.apache.commons.codec.digest.DigestUtils.sha256Hex;
 import static org.apache.commons.lang.StringUtils.isBlank;
-import static org.sonar.server.authentication.CookieUtils.createCookie;
-import static org.sonar.server.authentication.CookieUtils.findCookie;
+import static org.sonar.server.authentication.Cookies.findCookie;
+import static org.sonar.server.authentication.Cookies.newCookieBuilder;
 import static org.sonar.server.authentication.event.AuthenticationEvent.Source;
 
 public class OAuthCsrfVerifier {
@@ -42,7 +42,7 @@ public class OAuthCsrfVerifier {
     // Create a state token to prevent request forgery.
     // Store it in the session for later validation.
     String state = new BigInteger(130, new SecureRandom()).toString(32);
-    response.addCookie(createCookie(CSRF_STATE_COOKIE, sha256Hex(state), true, -1, request));
+    response.addCookie(newCookieBuilder(request).setName(CSRF_STATE_COOKIE).setValue(sha256Hex(state)).setHttpOnly(true).setExpiry(-1).build());
     return state;
   }
 
@@ -54,7 +54,7 @@ public class OAuthCsrfVerifier {
     String hashInCookie = cookie.getValue();
 
     // remove cookie
-    response.addCookie(createCookie(CSRF_STATE_COOKIE, null, true, 0, request));
+    response.addCookie(newCookieBuilder(request).setName(CSRF_STATE_COOKIE).setValue(null).setHttpOnly(true).setExpiry(0).build());
 
     String stateInRequest = request.getParameter("state");
     if (isBlank(stateInRequest) || !sha256Hex(stateInRequest).equals(hashInCookie)) {
index aa48ec86df3ad3427a66cc611b892162d8fb10a5..f191d39f6bb5ad176795e4fcc5189b758381faf8 100644 (file)
@@ -37,7 +37,6 @@ import org.sonar.server.authentication.event.AuthenticationException;
 import org.sonar.server.ws.ServletFilterHandler;
 
 import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
-import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED;
 import static org.sonar.server.authentication.ws.AuthenticationWs.AUTHENTICATION_CONTROLLER;
 import static org.sonarqube.ws.client.WsRequest.Method.POST;
 
@@ -81,21 +80,23 @@ public class LogoutAction extends ServletFilter implements AuthenticationWsActio
   }
 
   private void logout(HttpServletRequest request, HttpServletResponse response) {
+    generateAuthenticationEvent(request, response);
+    jwtHttpHandler.removeToken(request, response);
+  }
+
+  /**
+   * The generation of the authentication event should not prevent the removal of JWT cookie, that's why it's done in a separate method
+   */
+  private void generateAuthenticationEvent(HttpServletRequest request, HttpServletResponse response) {
     try {
-      generateAuthenticationEvent(request, response);
-      jwtHttpHandler.removeToken(request, response);
+      Optional<JwtHttpHandler.Token> token = jwtHttpHandler.getToken(request, response);
+      String userLogin = token.isPresent() ? token.get().getUserDto().getLogin() : null;
+      authenticationEvent.logoutSuccess(request, userLogin);
     } catch (AuthenticationException e) {
-      response.setStatus(HTTP_UNAUTHORIZED);
       authenticationEvent.logoutFailure(request, e.getMessage());
     }
   }
 
-  private void generateAuthenticationEvent(HttpServletRequest request, HttpServletResponse response) {
-    Optional<JwtHttpHandler.Token> token = jwtHttpHandler.getToken(request, response);
-    String userLogin = token.isPresent() ? token.get().getUserDto().getLogin() : null;
-    authenticationEvent.logoutSuccess(request, userLogin);
-  }
-
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
     // Nothing to do
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/CookieUtilsTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/CookieUtilsTest.java
deleted file mode 100644 (file)
index 02489f1..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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 javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class CookieUtilsTest {
-
-  private static final String HTTPS_HEADER = "X-Forwarded-Proto";
-
-  HttpServletRequest request = mock(HttpServletRequest.class);
-
-  @Test
-  public void create_cookie() throws Exception {
-    Cookie cookie = CookieUtils.createCookie("name", "value", true, 10, request);
-    assertThat(cookie.getName()).isEqualTo("name");
-    assertThat(cookie.getValue()).isEqualTo("value");
-    assertThat(cookie.isHttpOnly()).isTrue();
-    assertThat(cookie.getMaxAge()).isEqualTo(10);
-    assertThat(cookie.getSecure()).isFalse();
-  }
-
-  @Test
-  public void create_not_secured_cookie_when_header_is_not_http() throws Exception {
-    when(request.getHeader(HTTPS_HEADER)).thenReturn("http");
-    Cookie cookie = CookieUtils.createCookie("name", "value", true, 10, request);
-    assertThat(cookie.getSecure()).isFalse();
-  }
-
-  @Test
-  public void create_secured_cookie_when_X_Forwarded_Proto_header_is_https() throws Exception {
-    when(request.getHeader(HTTPS_HEADER)).thenReturn("https");
-    Cookie cookie = CookieUtils.createCookie("name", "value", true, 10, request);
-    assertThat(cookie.getSecure()).isTrue();
-  }
-
-  @Test
-  public void create_secured_cookie_when_X_Forwarded_Proto_header_is_HTTPS() throws Exception {
-    when(request.getHeader(HTTPS_HEADER)).thenReturn("HTTPS");
-    Cookie cookie = CookieUtils.createCookie("name", "value", true, 10, request);
-    assertThat(cookie.getSecure()).isTrue();
-  }
-
-  @Test
-  public void find_cookie() throws Exception {
-    Cookie cookie = new Cookie("name", "value");
-    when(request.getCookies()).thenReturn(new Cookie[] {cookie});
-
-    assertThat(CookieUtils.findCookie("name", request)).isPresent();
-    assertThat(CookieUtils.findCookie("NAME", request)).isEmpty();
-    assertThat(CookieUtils.findCookie("unknown", request)).isEmpty();
-  }
-
-  @Test
-  public void does_not_fail_to_find_cookie_when_no_cookie() throws Exception {
-    assertThat(CookieUtils.findCookie("unknown", request)).isEmpty();
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/authentication/CookiesTest.java b/server/sonar-server/src/test/java/org/sonar/server/authentication/CookiesTest.java
new file mode 100644 (file)
index 0000000..c9c4f01
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.authentication.Cookies.findCookie;
+import static org.sonar.server.authentication.Cookies.newCookieBuilder;
+
+public class CookiesTest {
+
+  private static final String HTTPS_HEADER = "X-Forwarded-Proto";
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  private HttpServletRequest request = mock(HttpServletRequest.class);
+
+  @Test
+  public void create_cookie() throws Exception {
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").setHttpOnly(true).setExpiry(10).build();
+    assertThat(cookie.getName()).isEqualTo("name");
+    assertThat(cookie.getValue()).isEqualTo("value");
+    assertThat(cookie.isHttpOnly()).isTrue();
+    assertThat(cookie.getMaxAge()).isEqualTo(10);
+    assertThat(cookie.getSecure()).isFalse();
+    assertThat(cookie.getPath()).isEqualTo("/");
+  }
+
+  @Test
+  public void create_cookie_without_value() throws Exception {
+    Cookie cookie = newCookieBuilder(request).setName("name").build();
+    assertThat(cookie.getName()).isEqualTo("name");
+    assertThat(cookie.getValue()).isNull();
+  }
+
+  @Test
+  public void create_cookie_when_web_context() throws Exception {
+    when(request.getContextPath()).thenReturn("/sonarqube");
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").setHttpOnly(true).setExpiry(10).build();
+    assertThat(cookie.getName()).isEqualTo("name");
+    assertThat(cookie.getValue()).isEqualTo("value");
+    assertThat(cookie.isHttpOnly()).isTrue();
+    assertThat(cookie.getMaxAge()).isEqualTo(10);
+    assertThat(cookie.getSecure()).isFalse();
+    assertThat(cookie.getPath()).isEqualTo("/sonarqube");
+  }
+
+  @Test
+  public void create_not_secured_cookie_when_header_is_not_http() throws Exception {
+    when(request.getHeader(HTTPS_HEADER)).thenReturn("http");
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").setHttpOnly(true).setExpiry(10).build();
+    assertThat(cookie.getSecure()).isFalse();
+  }
+
+  @Test
+  public void create_secured_cookie_when_X_Forwarded_Proto_header_is_https() throws Exception {
+    when(request.getHeader(HTTPS_HEADER)).thenReturn("https");
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").setHttpOnly(true).setExpiry(10).build();
+    assertThat(cookie.getSecure()).isTrue();
+  }
+
+  @Test
+  public void create_secured_cookie_when_X_Forwarded_Proto_header_is_HTTPS() throws Exception {
+    when(request.getHeader(HTTPS_HEADER)).thenReturn("HTTPS");
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").setHttpOnly(true).setExpiry(10).build();
+    assertThat(cookie.getSecure()).isTrue();
+  }
+
+  @Test
+  public void find_cookie() throws Exception {
+    Cookie cookie = newCookieBuilder(request).setName("name").setValue("value").build();
+    when(request.getCookies()).thenReturn(new Cookie[] {cookie});
+
+    assertThat(findCookie("name", request)).isPresent();
+    assertThat(findCookie("NAME", request)).isEmpty();
+    assertThat(findCookie("unknown", request)).isEmpty();
+  }
+
+  @Test
+  public void does_not_fail_to_find_cookie_when_no_cookie() throws Exception {
+    assertThat(findCookie("unknown", request)).isEmpty();
+  }
+
+  @Test
+  public void fail_with_NPE_when_cookie_name_is_null() throws Exception {
+    expectedException.expect(NullPointerException.class);
+    newCookieBuilder(request).setName(null);
+  }
+
+  @Test
+  public void fail_with_NPE_when_cookie_has_no_name() throws Exception {
+    expectedException.expect(NullPointerException.class);
+    newCookieBuilder(request).setName(null);
+  }
+
+}
index 1382808223ce8955b6165186892c0dc813a437aa..41949c870c3d230e472c7dbdbb0a0e7e93405901 100644 (file)
@@ -40,7 +40,6 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -113,8 +112,7 @@ public class LogoutActionTest {
     executeRequest();
 
     verify(authenticationEvent).logoutFailure(request, "error!");
-    verify(jwtHttpHandler, never()).removeToken(any(HttpServletRequest.class), any(HttpServletResponse.class));
-    verify(response).setStatus(401);
+    verify(jwtHttpHandler).removeToken(any(HttpServletRequest.class), any(HttpServletResponse.class));
     verifyZeroInteractions(chain);
   }