Skip to content

Commit 32f5fb5

Browse files
committed
ExceptionTranslationFilter does not handle committed responses
Fixes: gh-5273
1 parent f7f6798 commit 32f5fb5

File tree

3 files changed

+44
-15
lines changed

3 files changed

+44
-15
lines changed

config/src/test/groovy/org/springframework/security/config/http/InterceptUrlConfigTests.groovy

+4
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,15 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
131131
when: 'user cannot access otheruser'
132132
request = new MockHttpServletRequest(method:'GET', servletPath : '/user/otheruser/abc')
133133
login(request, 'user', 'password')
134+
response = new MockHttpServletResponse()
134135
chain.reset()
135136
springSecurityFilterChain.doFilter(request,response,chain)
136137
then: 'The response is OK'
137138
response.status == HttpServletResponse.SC_FORBIDDEN
138139
when: 'user can access case insensitive URL'
139140
request = new MockHttpServletRequest(method:'GET', servletPath : '/USER/user/abc')
140141
login(request, 'user', 'password')
142+
response = new MockHttpServletResponse()
141143
chain.reset()
142144
springSecurityFilterChain.doFilter(request,response,chain)
143145
then: 'The response is OK'
@@ -164,13 +166,15 @@ class InterceptUrlConfigTests extends AbstractHttpConfigTests {
164166
when: 'user cannot access otheruser'
165167
request = new MockHttpServletRequest(method:'GET', servletPath : '/user/otheruser/abc')
166168
login(request, 'user', 'password')
169+
response = new MockHttpServletResponse()
167170
chain.reset()
168171
springSecurityFilterChain.doFilter(request,response,chain)
169172
then: 'The response is OK'
170173
response.status == HttpServletResponse.SC_FORBIDDEN
171174
when: 'user can access case insensitive URL'
172175
request = new MockHttpServletRequest(method:'GET', servletPath : '/USER/user/abc')
173176
login(request, 'user', 'password')
177+
response = new MockHttpServletResponse()
174178
chain.reset()
175179
springSecurityFilterChain.doFilter(request,response,chain)
176180
then: 'The response is OK'

web/src/main/java/org/springframework/security/web/access/ExceptionTranslationFilter.java

+3
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
135135
}
136136

137137
if (ase != null) {
138+
if (response.isCommitted()) {
139+
throw new ServletException("Unable to handle the Spring Security Exception because the response is already committed.", ex);
140+
}
138141
handleSpringSecurityException(request, response, chain, ase);
139142
}
140143
else {

web/src/test/java/org/springframework/security/web/access/ExceptionTranslationFilterTests.java

+37-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@
1515
*/
1616
package org.springframework.security.web.access;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
20+
import static org.assertj.core.api.Assertions.fail;
21+
import static org.mockito.Matchers.any;
22+
import static org.mockito.Mockito.doThrow;
23+
import static org.mockito.Mockito.mock;
24+
import static org.mockito.Mockito.verifyZeroInteractions;
25+
26+
import java.io.IOException;
27+
import java.util.Locale;
28+
29+
import javax.servlet.FilterChain;
30+
import javax.servlet.ServletException;
31+
import javax.servlet.http.HttpServletRequest;
32+
import javax.servlet.http.HttpServletResponse;
33+
import javax.servlet.http.HttpSession;
34+
1835
import org.junit.After;
1936
import org.junit.Before;
2037
import org.junit.Test;
@@ -36,20 +53,6 @@
3653
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
3754
import org.springframework.security.web.savedrequest.SavedRequest;
3855

39-
import javax.servlet.FilterChain;
40-
import javax.servlet.ServletException;
41-
import javax.servlet.http.HttpServletRequest;
42-
import javax.servlet.http.HttpServletResponse;
43-
import javax.servlet.http.HttpSession;
44-
import java.io.IOException;
45-
import java.util.Locale;
46-
47-
import static org.assertj.core.api.Assertions.assertThat;
48-
import static org.assertj.core.api.Assertions.fail;
49-
import static org.mockito.Matchers.any;
50-
import static org.mockito.Mockito.doThrow;
51-
import static org.mockito.Mockito.mock;
52-
5356
/**
5457
* Tests {@link ExceptionTranslationFilter}.
5558
*
@@ -302,7 +305,26 @@ public void thrownIOExceptionServletExceptionAndRuntimeExceptionsAreRethrown()
302305
}
303306
}
304307

305-
private final AuthenticationEntryPoint mockEntryPoint = new AuthenticationEntryPoint() {
308+
@Test
309+
public void doFilterWhenResponseCommittedThenRethrowsException() throws Exception {
310+
this.mockEntryPoint = mock(AuthenticationEntryPoint.class);
311+
FilterChain chain = (request, response) -> {
312+
HttpServletResponse httpResponse = (HttpServletResponse) response;
313+
httpResponse.sendError(HttpServletResponse.SC_BAD_REQUEST);
314+
throw new AccessDeniedException("Denied");
315+
};
316+
MockHttpServletRequest request = new MockHttpServletRequest();
317+
MockHttpServletResponse response = new MockHttpServletResponse();
318+
ExceptionTranslationFilter filter = new ExceptionTranslationFilter(mockEntryPoint);
319+
320+
assertThatThrownBy(() -> filter.doFilter(request, response, chain))
321+
.isInstanceOf(ServletException.class)
322+
.hasCauseInstanceOf(AccessDeniedException.class);
323+
324+
verifyZeroInteractions(mockEntryPoint);
325+
}
326+
327+
private AuthenticationEntryPoint mockEntryPoint = new AuthenticationEntryPoint() {
306328
public void commence(HttpServletRequest request, HttpServletResponse response,
307329
AuthenticationException authException) throws IOException,
308330
ServletException {

0 commit comments

Comments
 (0)