Skip to content

Commit 7bde3ec

Browse files
committed
Fix ChannelProcessingFilter to skip decision if response already committed
In this commit, we quickly fix a bug in ChannelProcessingFilter#doFilter where if filterInvocation.getResponse().isCommitted() is checked before decide, it will not pass further into the filter, which is an error. Perhaps in the future it would be better to extend the ChannelDecisionManager interface directly, but it is deprecated and this would be difficult and beyond the scope of this commit. Closes: gh-6721 Signed-off-by: Andrey Litvitski <[email protected]>
1 parent 6f1232c commit 7bde3ec

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

web/src/main/java/org/springframework/security/web/access/channel/ChannelProcessingFilter.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
* over HTTPS.
8484
*
8585
* @author Ben Alex
86+
* @author Andrey Litvitski
8687
* @deprecated see {@link org.springframework.security.web.transport.HttpsRedirectFilter}
8788
*/
8889
@Deprecated
@@ -125,10 +126,12 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
125126
HttpServletResponse response = (HttpServletResponse) res;
126127
FilterInvocation filterInvocation = new FilterInvocation(request, response, chain);
127128
Collection<ConfigAttribute> attributes = this.securityMetadataSource.getAttributes(filterInvocation);
128-
if (attributes != null) {
129+
boolean committedBefore = filterInvocation.getResponse().isCommitted();
130+
if (attributes != null && !committedBefore) {
129131
this.logger.debug(LogMessage.format("Request: %s; ConfigAttributes: %s", filterInvocation, attributes));
130132
this.channelDecisionManager.decide(filterInvocation, attributes);
131-
if (filterInvocation.getResponse().isCommitted()) {
133+
boolean committedAfter = filterInvocation.getResponse().isCommitted();
134+
if (committedAfter) {
132135
return;
133136
}
134137
}

web/src/test/java/org/springframework/security/web/access/channel/ChannelProcessingFilterTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@
3232
import static org.assertj.core.api.Assertions.assertThat;
3333
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3434
import static org.mockito.Mockito.mock;
35+
import static org.mockito.Mockito.verify;
3536
import static org.springframework.security.web.servlet.TestMockHttpServletRequests.get;
3637

3738
/**
3839
* Tests {@link ChannelProcessingFilter}.
3940
*
4041
* @author Ben Alex
42+
* @author Andrey Litvitski
4143
*/
4244
public class ChannelProcessingFilterTests {
4345

@@ -123,6 +125,21 @@ public void testGetterSetters() {
123125
filter.afterPropertiesSet();
124126
}
125127

128+
@Test
129+
public void testDoFilterWhenResponseAlreadyCommittedBeforeFilter() throws Exception {
130+
ChannelProcessingFilter filter = new ChannelProcessingFilter();
131+
filter.setChannelDecisionManager(new MockChannelDecisionManager(false, "MOCK"));
132+
MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", true, "MOCK");
133+
filter.setSecurityMetadataSource(fids);
134+
MockHttpServletRequest request = get("/path").build();
135+
MockHttpServletResponse response = new MockHttpServletResponse();
136+
// this will set response.isCommitted() == true
137+
response.flushBuffer();
138+
FilterChain chain = mock(FilterChain.class);
139+
filter.doFilter(request, response, chain);
140+
verify(chain).doFilter(request, response);
141+
}
142+
126143
private class MockChannelDecisionManager implements ChannelDecisionManager {
127144

128145
private String supportAttribute;

0 commit comments

Comments
 (0)