From 3099f921544c0f2897150299ba421210fb8f8d25 Mon Sep 17 00:00:00 2001 From: Gunnar Hillert Date: Wed, 29 Apr 2015 00:08:46 -0400 Subject: [PATCH] SEC-2944 Add HttpStatusReturningLogoutSuccessHandler * Add HttpStatusReturningLogoutSuccessHandler to provide better logout capabilities for RESTful APIs --- ...tpStatusReturningLogoutSuccessHandler.java | 69 +++++++++++++++++ ...tusReturningLogoutSuccessHandlerTests.java | 77 +++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 web/src/main/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandler.java create mode 100644 web/src/test/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandlerTests.java diff --git a/web/src/main/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandler.java b/web/src/main/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandler.java new file mode 100644 index 0000000000..6de9d677ed --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandler.java @@ -0,0 +1,69 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.springframework.security.web.authentication.logout; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.http.HttpStatus; +import org.springframework.security.core.Authentication; +import org.springframework.util.Assert; + +/** + * Implementation of the {@link LogoutSuccessHandler}. By default returns an HTTP + * status code of {@code 200}. This is useful in REST-type scenarios where a + * redirect upon a successful logout is not desired. + * + * @author Gunnar Hillert + * @since 4.0.2 + */ +public class HttpStatusReturningLogoutSuccessHandler implements LogoutSuccessHandler { + + private final HttpStatus httpStatusToReturn; + + /** + * Initialize the {@code HttpStatusLogoutSuccessHandler} with a user-defined + * {@link HttpStatus}. + * + * @param httpStatusToReturn Must not be {@code null}. + */ + public HttpStatusReturningLogoutSuccessHandler(HttpStatus httpStatusToReturn) { + Assert.notNull(httpStatusToReturn, "The provided HttpStatus must not be null."); + this.httpStatusToReturn = httpStatusToReturn; + } + + /** + * Initialize the {@code HttpStatusLogoutSuccessHandler} with the default + * {@link HttpStatus#OK}. + */ + public HttpStatusReturningLogoutSuccessHandler() { + this.httpStatusToReturn = HttpStatus.OK; + } + + /** + * Implementation of {@link LogoutSuccessHandler#onLogoutSuccess(HttpServletRequest, HttpServletResponse, Authentication)}. + * Sets the status on the {@link HttpServletResponse}. + */ + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { + response.setStatus(httpStatusToReturn.value()); + response.getWriter().flush(); + } + +} diff --git a/web/src/test/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandlerTests.java b/web/src/test/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandlerTests.java new file mode 100644 index 0000000000..4c4c6b5712 --- /dev/null +++ b/web/src/test/java/org/springframework/security/web/authentication/logout/HttpStatusReturningLogoutSuccessHandlerTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.springframework.security.web.authentication.logout; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.mock; + +import org.junit.Assert; +import org.junit.Test; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.core.Authentication; + +/** + * @author Gunnar Hillert + */ +public class HttpStatusReturningLogoutSuccessHandlerTests { + + @Test + public void testDefaultHttpStatusBeingReturned() throws Exception { + final HttpStatusReturningLogoutSuccessHandler lsh = new HttpStatusReturningLogoutSuccessHandler(); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + lsh.onLogoutSuccess(request, response, mock(Authentication.class)); + + assertNull(request.getSession(false)); + assertNull(response.getRedirectedUrl()); + assertNull(response.getForwardedUrl()); + assertEquals(HttpStatus.OK.value(), response.getStatus()); + } + + @Test + public void testCustomHttpStatusBeingReturned() throws Exception { + final HttpStatusReturningLogoutSuccessHandler lsh = new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT); + + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + + lsh.onLogoutSuccess(request, response, mock(Authentication.class)); + + assertNull(request.getSession(false)); + assertNull(response.getRedirectedUrl()); + assertNull(response.getForwardedUrl()); + assertEquals(HttpStatus.NO_CONTENT.value(), response.getStatus()); + } + + @Test + public void testThatSettNullHttpStatusThrowsException() throws Exception { + + try { + new HttpStatusReturningLogoutSuccessHandler(null); + } + catch (IllegalArgumentException e) { + assertEquals("The provided HttpStatus must not be null.", e.getMessage()); + return; + } + + Assert.fail("Expected an IllegalArgumentException to be thrown."); + } + +}