Skip to content

Commit 91728ef

Browse files
committed
Fix HttpServlet3RequestFactory Logout Handlers
Previously there was a problem with Servlet API logout integration when Servlet API was configured before log out. This ensures that logout handlers is a reference to the logout handlers vs copying the logout handlers. This ensures that the ordering does not matter. Closes gh-4760
1 parent b055f8b commit 91728ef

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/ServletApiConfigurerTests.java

+39
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.Test;
2323
import org.springframework.beans.factory.annotation.Autowired;
2424
import org.springframework.context.annotation.Bean;
25+
import org.springframework.context.annotation.Configuration;
2526
import org.springframework.security.access.AccessDeniedException;
2627
import org.springframework.security.authentication.AuthenticationManager;
2728
import org.springframework.security.authentication.AuthenticationTrustResolver;
@@ -44,10 +45,14 @@
4445
import org.springframework.security.web.authentication.logout.LogoutSuccessEventPublishingLogoutHandler;
4546
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
4647
import org.springframework.test.web.servlet.MockMvc;
48+
import org.springframework.test.web.servlet.MvcResult;
49+
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
4750
import org.springframework.web.bind.annotation.GetMapping;
4851
import org.springframework.web.bind.annotation.RestController;
52+
import org.springframework.web.context.ConfigurableWebApplicationContext;
4953

5054
import javax.servlet.Filter;
55+
import javax.servlet.ServletException;
5156
import javax.servlet.http.HttpServletRequest;
5257
import javax.servlet.http.HttpServletResponse;
5358

@@ -60,6 +65,7 @@
6065
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
6166
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
6267
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
68+
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
6369
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
6470
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
6571

@@ -329,6 +335,39 @@ protected void configure(HttpSecurity http) throws Exception {
329335
}
330336
}
331337

338+
@Test
339+
public void logoutServletApiWhenCsrfDisabled() throws Exception {
340+
ConfigurableWebApplicationContext context = this.spring.register(CsrfDisabledConfig.class).getContext();
341+
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(context)
342+
.apply(springSecurity())
343+
.build();
344+
MvcResult mvcResult = mockMvc.perform(get("/"))
345+
.andReturn();
346+
assertThat(mvcResult.getRequest().getSession(false)).isNull();
347+
}
348+
349+
@Configuration
350+
@EnableWebSecurity
351+
static class CsrfDisabledConfig extends WebSecurityConfigurerAdapter {
352+
@Override
353+
protected void configure(HttpSecurity http) throws Exception {
354+
// @formatter:off
355+
http
356+
.csrf().disable();
357+
// @formatter:on
358+
}
359+
360+
@RestController
361+
static class LogoutController {
362+
@GetMapping("/")
363+
String logout(HttpServletRequest request) throws ServletException {
364+
request.getSession().setAttribute("foo", "bar");
365+
request.logout();
366+
return "logout";
367+
}
368+
}
369+
}
370+
332371
private <T extends Filter> T getFilter(Class<T> filterClass) {
333372
return (T) getFilters().stream()
334373
.filter(filterClass::isInstance)

web/src/main/java/org/springframework/security/web/servletapi/HttpServlet3RequestFactory.java

+7-6
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import org.springframework.security.core.context.SecurityContext;
4343
import org.springframework.security.core.context.SecurityContextHolder;
4444
import org.springframework.security.web.AuthenticationEntryPoint;
45-
import org.springframework.security.web.authentication.logout.CompositeLogoutHandler;
4645
import org.springframework.security.web.authentication.logout.LogoutHandler;
4746
import org.springframework.util.Assert;
4847
import org.springframework.util.CollectionUtils;
@@ -80,7 +79,7 @@ final class HttpServlet3RequestFactory implements HttpServletRequestFactory {
8079
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
8180
private AuthenticationEntryPoint authenticationEntryPoint;
8281
private AuthenticationManager authenticationManager;
83-
private LogoutHandler logoutHandler;
82+
private List<LogoutHandler> logoutHandlers;
8483

8584
HttpServlet3RequestFactory(String rolePrefix) {
8685
this.rolePrefix = rolePrefix;
@@ -144,7 +143,7 @@ public void setAuthenticationManager(AuthenticationManager authenticationManager
144143
* {@link HttpServletRequest#logout()}.
145144
*/
146145
public void setLogoutHandlers(List<LogoutHandler> logoutHandlers) {
147-
this.logoutHandler = CollectionUtils.isEmpty(logoutHandlers) ? null : new CompositeLogoutHandler(logoutHandlers);
146+
this.logoutHandlers = logoutHandlers;
148147
}
149148

150149
/**
@@ -244,16 +243,18 @@ public void login(String username, String password) throws ServletException {
244243

245244
@Override
246245
public void logout() throws ServletException {
247-
LogoutHandler handler = HttpServlet3RequestFactory.this.logoutHandler;
248-
if (handler == null) {
246+
List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
247+
if (CollectionUtils.isEmpty(handlers)) {
249248
HttpServlet3RequestFactory.this.logger.debug(
250249
"logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
251250
super.logout();
252251
return;
253252
}
254253
Authentication authentication = SecurityContextHolder.getContext()
255254
.getAuthentication();
256-
handler.logout(this, this.response, authentication);
255+
for (LogoutHandler handler : handlers) {
256+
handler.logout(this, this.response, authentication);
257+
}
257258
}
258259

259260
private boolean isAuthenticated() {

0 commit comments

Comments
 (0)