mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-01 10:59:16 +00:00
Default logout negotiation in Java Configuration
This commit adds content negotiation for log out. Fixes gh-3282
This commit is contained in:
parent
4093690322
commit
510cd59980
@ -31,6 +31,8 @@ import org.springframework.security.web.authentication.DelegatingAuthenticationE
|
||||
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
|
||||
import org.springframework.security.web.authentication.RememberMeServices;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
||||
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;
|
||||
@ -143,16 +145,11 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
}
|
||||
|
||||
public void init(B http) throws Exception {
|
||||
registerDefaultAuthenticationEntryPoint(http);
|
||||
registerDefaults(http);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void registerDefaultAuthenticationEntryPoint(B http) {
|
||||
ExceptionHandlingConfigurer<B> exceptionHandling = http
|
||||
.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
if (exceptionHandling == null) {
|
||||
return;
|
||||
}
|
||||
private void registerDefaults(B http) {
|
||||
ContentNegotiationStrategy contentNegotiationStrategy = http
|
||||
.getSharedObject(ContentNegotiationStrategy.class);
|
||||
if (contentNegotiationStrategy == null) {
|
||||
@ -164,9 +161,29 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
|
||||
MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML,
|
||||
MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML);
|
||||
preferredMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
|
||||
|
||||
registerDefaultEntryPoint(http, preferredMatcher);
|
||||
registerDefaultLogoutSuccessHandler(http, preferredMatcher);
|
||||
}
|
||||
|
||||
private void registerDefaultEntryPoint(B http, RequestMatcher preferredMatcher) {
|
||||
ExceptionHandlingConfigurer<B> exceptionHandling = http
|
||||
.getConfigurer(ExceptionHandlingConfigurer.class);
|
||||
if (exceptionHandling == null) {
|
||||
return;
|
||||
}
|
||||
exceptionHandling.defaultAuthenticationEntryPointFor(
|
||||
postProcess(authenticationEntryPoint), preferredMatcher);
|
||||
}
|
||||
|
||||
private void registerDefaultLogoutSuccessHandler(B http, RequestMatcher preferredMatcher) {
|
||||
LogoutConfigurer<B> logout = http
|
||||
.getConfigurer(LogoutConfigurer.class);
|
||||
if (logout == null) {
|
||||
return;
|
||||
}
|
||||
LogoutConfigurer<B> handler = logout.defaultLogoutSuccessHandlerFor(
|
||||
postProcess(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.NO_CONTENT)), preferredMatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,6 +16,7 @@
|
||||
package org.springframework.security.config.annotation.web.configurers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
@ -24,7 +25,9 @@ import org.springframework.security.config.annotation.SecurityConfigurer;
|
||||
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.DelegatingLogoutSuccessHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter;
|
||||
import org.springframework.security.web.authentication.logout.LogoutHandler;
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
@ -71,6 +74,9 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
private boolean permitAll;
|
||||
private boolean customLogoutSuccess;
|
||||
|
||||
private LinkedHashMap<RequestMatcher, LogoutSuccessHandler> defaultLogoutSuccessHandlerMappings =
|
||||
new LinkedHashMap<RequestMatcher, LogoutSuccessHandler>();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
* @see HttpSecurity#logout()
|
||||
@ -205,6 +211,27 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a default {@link LogoutSuccessHandler} to be used which prefers being invoked
|
||||
* for the provided {@link RequestMatcher}. If no {@link LogoutSuccessHandler} is
|
||||
* specified a {@link SimpleUrlLogoutSuccessHandler} will be used.
|
||||
* If any default {@link LogoutSuccessHandler} instances are configured, then a
|
||||
* {@link DelegatingLogoutSuccessHandler} will be used that defaults to a
|
||||
* {@link SimpleUrlLogoutSuccessHandler}.
|
||||
*
|
||||
* @param handler the {@link LogoutSuccessHandler} to use
|
||||
* @param preferredMatcher the {@link RequestMatcher} for this default
|
||||
* {@link LogoutSuccessHandler}
|
||||
* @return the {@link LogoutConfigurer} for further customizations
|
||||
*/
|
||||
public LogoutConfigurer<H> defaultLogoutSuccessHandlerFor(
|
||||
LogoutSuccessHandler handler, RequestMatcher preferredMatcher) {
|
||||
Assert.notNull(handler, "handler cannot be null");
|
||||
Assert.notNull(preferredMatcher, "preferredMatcher cannot be null");
|
||||
this.defaultLogoutSuccessHandlerMappings.put(preferredMatcher, handler);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grants access to the {@link #logoutSuccessUrl(String)} and the
|
||||
* {@link #logoutUrl(String)} for every user.
|
||||
@ -224,12 +251,22 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
|
||||
* @return the {@link LogoutSuccessHandler} to use
|
||||
*/
|
||||
private LogoutSuccessHandler getLogoutSuccessHandler() {
|
||||
if (logoutSuccessHandler != null) {
|
||||
return logoutSuccessHandler;
|
||||
LogoutSuccessHandler handler = this.logoutSuccessHandler;
|
||||
if (handler == null) {
|
||||
handler = createDefaultSuccessHandler();
|
||||
}
|
||||
SimpleUrlLogoutSuccessHandler logoutSuccessHandler = new SimpleUrlLogoutSuccessHandler();
|
||||
logoutSuccessHandler.setDefaultTargetUrl(logoutSuccessUrl);
|
||||
return logoutSuccessHandler;
|
||||
return handler;
|
||||
}
|
||||
|
||||
private LogoutSuccessHandler createDefaultSuccessHandler() {
|
||||
SimpleUrlLogoutSuccessHandler urlLogoutHandler = new SimpleUrlLogoutSuccessHandler();
|
||||
urlLogoutHandler.setDefaultTargetUrl(logoutSuccessUrl);
|
||||
if(defaultLogoutSuccessHandlerMappings.isEmpty()) {
|
||||
return urlLogoutHandler;
|
||||
}
|
||||
DelegatingLogoutSuccessHandler successHandler = new DelegatingLogoutSuccessHandler(defaultLogoutSuccessHandlerMappings);
|
||||
successHandler.setDefaultLogoutSuccessHandler(urlLogoutHandler);
|
||||
return successHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -26,6 +26,9 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
import org.springframework.security.config.annotation.web.configurers.LogoutConfigurerTests.RememberMeNoLogoutHandler;
|
||||
import org.springframework.security.web.authentication.RememberMeServices
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||
import org.springframework.security.web.util.matcher.RequestMatcher
|
||||
|
||||
/**
|
||||
*
|
||||
@ -33,6 +36,24 @@ import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
*/
|
||||
class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
|
||||
def defaultLogoutSuccessHandlerForNullLogoutHandler() {
|
||||
setup:
|
||||
LogoutConfigurer config = new LogoutConfigurer();
|
||||
when:
|
||||
config.defaultLogoutSuccessHandlerFor(null, Mock(RequestMatcher))
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def defaultLogoutSuccessHandlerForNullMatcher() {
|
||||
setup:
|
||||
LogoutConfigurer config = new LogoutConfigurer();
|
||||
when:
|
||||
config.defaultLogoutSuccessHandlerFor(Mock(LogoutSuccessHandler), null)
|
||||
then:
|
||||
thrown(IllegalArgumentException)
|
||||
}
|
||||
|
||||
def "logout ObjectPostProcessor"() {
|
||||
setup:
|
||||
AnyObjectPostProcessor opp = Mock()
|
||||
@ -145,4 +166,35 @@ class LogoutConfigurerTests extends BaseSpringSpec {
|
||||
.rememberMeServices(REMEMBER_ME)
|
||||
}
|
||||
}
|
||||
|
||||
def "LogoutConfigurer content negotiation default redirects"() {
|
||||
setup:
|
||||
loadConfig(LogoutHandlerContentNegotiation)
|
||||
when:
|
||||
login()
|
||||
request.method = 'POST'
|
||||
request.servletPath = '/logout'
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == 302
|
||||
response.redirectedUrl == '/login?logout'
|
||||
}
|
||||
|
||||
// gh-3282
|
||||
def "LogoutConfigurer content negotiation json 201"() {
|
||||
setup:
|
||||
loadConfig(LogoutHandlerContentNegotiation)
|
||||
when:
|
||||
login()
|
||||
request.method = 'POST'
|
||||
request.servletPath = '/logout'
|
||||
request.addHeader('Accept', 'application/json')
|
||||
springSecurityFilterChain.doFilter(request,response,chain)
|
||||
then:
|
||||
response.status == 204
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class LogoutHandlerContentNegotiation extends WebSecurityConfigurerAdapter {
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user